diff --git a/_CoqProject b/_CoqProject
index 5cabedc486f98ba582a375296f19b288b1ffad0a..01846539ca44e3e0766dc7fbe03aea7924edba0c 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -36,3 +36,4 @@ theories/typing/own.v
 theories/typing/borrow.v
 theories/typing/product_split.v
 theories/typing/type_sum.v
+theories/typing/fixpoint.v
diff --git a/theories/typing/fixpoint.v b/theories/typing/fixpoint.v
new file mode 100644
index 0000000000000000000000000000000000000000..c517f2839729de02395a7474f13037d5bfa6be2e
--- /dev/null
+++ b/theories/typing/fixpoint.v
@@ -0,0 +1,151 @@
+From gpfsl.lang Require Import proofmode.
+From lrust.typing Require Export lft_contexts type bool.
+Set Default Proof Using "Type".
+Import uPred.
+
+Section fixpoint_def.
+  Context `{typeG Σ}.
+  Context (T : type → type) {HT: TypeContractive T}.
+
+  Global Instance type_inhabited : Inhabited type := populate bool.
+
+  Local Instance type_2_contractive : Contractive (Nat.iter 2 T).
+  Proof using Type*.
+    intros n ? **. simpl.
+    by apply dist_later_dist, type_dist2_dist_later, HT, HT, type_later_dist2_later.
+  Qed.
+
+  Definition type_fixpoint : type := fixpointK 2 T.
+
+  (* The procedure for computing ty_lfts and ty_wf_E for fixpoints is
+     the following:
+       - We do a first pass for computing [ty_lfts].
+       - In a second pass, we compute [ty_wf_E], by using the result of the
+         first pass.
+     I believe this gives the right sets for all types that we can define in
+     Rust, but I do not have any proof of this.
+     TODO : investigate this in more detail. *)
+  Global Instance type_fixpoint_wf `{∀ `{!TyWf ty}, TyWf (T ty)} : TyWf type_fixpoint :=
+    let lfts :=
+      let _ : TyWf type_fixpoint := {| ty_lfts := []; ty_wf_E := [] |} in
+      (T type_fixpoint).(ty_lfts)
+    in
+    let wf_E :=
+      let _ : TyWf type_fixpoint := {| ty_lfts := lfts; ty_wf_E := [] |} in
+      (T type_fixpoint).(ty_wf_E)
+    in
+    {| ty_lfts := lfts; ty_wf_E := wf_E |}.
+End fixpoint_def.
+
+Lemma type_fixpoint_ne `{typeG Σ} (T1 T2 : type → type)
+    `{!TypeContractive T1, !TypeContractive T2} n :
+  (∀ t, T1 t ≡{n}≡ T2 t) → type_fixpoint T1 ≡{n}≡ type_fixpoint T2.
+Proof. eapply fixpointK_ne; apply type_contractive_ne, _. Qed.
+
+Section fixpoint.
+  Context `{typeG Σ}.
+  Context (T : type → type) {HT: TypeContractive T}.
+
+  Global Instance fixpoint_copy :
+    (∀ `(!Copy ty), Copy (T ty)) → Copy (type_fixpoint T).
+  Proof.
+    intros ?. unfold type_fixpoint. apply fixpointK_ind.
+    - apply type_contractive_ne, _.
+    - apply copy_equiv.
+    - exists bool. apply _.
+    - done.
+    - (* If Copy was an Iris assertion, this would be trivial -- we'd just
+         use limit_preserving_and directly. However, on the Coq side, it is
+         more convenient as a record -- so this is where we pay. *)
+      eapply (limit_preserving_ext (λ _, _ ∧ _)).
+      { split; (intros [H1 H2]; split; [apply H1|apply H2]). }
+      apply limit_preserving_and; repeat (apply limit_preserving_forall=> ?).
+      + apply bi.limit_preserving_Persistent; solve_proper.
+      + apply limit_preserving_impl, bi.limit_preserving_entails;
+        solve_proper_core ltac:(fun _ => eapply ty_size_ne || f_equiv).
+  Qed.
+
+  Global Instance fixpoint_send :
+    (∀ `(!Send ty), Send (T ty)) → Send (type_fixpoint T).
+  Proof.
+    intros ?. unfold type_fixpoint. apply fixpointK_ind.
+    - apply type_contractive_ne, _.
+    - apply send_equiv.
+    - exists bool. apply _.
+    - done.
+    - repeat (apply limit_preserving_forall=> ?).
+      apply bi.limit_preserving_entails; solve_proper.
+  Qed.
+
+  Global Instance fixpoint_sync :
+    (∀ `(!Sync ty), Sync (T ty)) → Sync (type_fixpoint T).
+  Proof.
+    intros ?. unfold type_fixpoint. apply fixpointK_ind.
+    - apply type_contractive_ne, _.
+    - apply sync_equiv.
+    - exists bool. apply _.
+    - done.
+    - repeat (apply limit_preserving_forall=> ?).
+      apply bi.limit_preserving_entails; solve_proper.
+  Qed.
+
+  Lemma fixpoint_unfold_eqtype E L : eqtype E L (type_fixpoint T) (T (type_fixpoint T)).
+  Proof.
+    unfold eqtype, subtype, type_incl.
+    setoid_rewrite <-fixpointK_unfold; [| by apply type_contractive_ne, _..].
+    split; iIntros (qL) "_ !# _"; (iSplit; first done); iSplit; iIntros "!#*$".
+  Qed.
+End fixpoint.
+
+Section subtyping.
+  Context `{typeG Σ} (E : elctx) (L : llctx).
+
+  (* TODO : is there a way to declare these as a [Proper] instances ? *)
+  Lemma fixpoint_mono T1 `{!TypeContractive T1} T2 `{!TypeContractive T2} :
+    (∀ ty1 ty2, subtype E L ty1 ty2 → subtype E L (T1 ty1) (T2 ty2)) →
+    subtype E L (type_fixpoint T1) (type_fixpoint T2).
+  Proof.
+    intros H12. rewrite /type_fixpoint. apply fixpointK_ind.
+    - apply type_contractive_ne, _.
+    - intros ?? EQ ?. etrans; last done. by apply equiv_subtype.
+    - by eexists _.
+    - intros. setoid_rewrite (fixpoint_unfold_eqtype T2). by apply H12.
+    - repeat (apply limit_preserving_forall=> ?).
+      apply bi.limit_preserving_entails; solve_proper.
+  Qed.
+
+  Lemma fixpoint_proper T1 `{TypeContractive T1} T2 `{TypeContractive T2} :
+    (∀ ty1 ty2, eqtype E L ty1 ty2 → eqtype E L (T1 ty1) (T2 ty2)) →
+    eqtype E L (type_fixpoint T1) (type_fixpoint T2).
+  Proof.
+    intros H12. rewrite /type_fixpoint. apply fixpointK_ind.
+    - apply type_contractive_ne, _.
+    - intros ?? EQ ?. etrans; last done. by apply equiv_eqtype.
+    - by eexists _.
+    - intros. setoid_rewrite (fixpoint_unfold_eqtype T2). by apply H12.
+    - apply limit_preserving_and; repeat (apply limit_preserving_forall=> ?);
+        apply bi.limit_preserving_entails; solve_proper.
+  Qed.
+
+  Lemma fixpoint_unfold_subtype_l ty T `{TypeContractive T} :
+    subtype E L ty (T (type_fixpoint T)) → subtype E L ty (type_fixpoint T).
+  Proof. intros. by rewrite fixpoint_unfold_eqtype. Qed.
+  Lemma fixpoint_unfold_subtype_r ty T `{TypeContractive T} :
+    subtype E L (T (type_fixpoint T)) ty → subtype E L (type_fixpoint T) ty.
+  Proof. intros. by rewrite fixpoint_unfold_eqtype. Qed.
+  Lemma fixpoint_unfold_eqtype_l ty T `{TypeContractive T} :
+    eqtype E L ty (T (type_fixpoint T)) → eqtype E L ty (type_fixpoint T).
+  Proof. intros. by rewrite fixpoint_unfold_eqtype. Qed.
+  Lemma fixpoint_unfold_eqtype_r ty T `{TypeContractive T} :
+    eqtype E L (T (type_fixpoint T)) ty → eqtype E L (type_fixpoint T) ty.
+  Proof. intros. by rewrite fixpoint_unfold_eqtype. Qed.
+End subtyping.
+
+Hint Resolve fixpoint_mono fixpoint_proper : lrust_typing.
+
+(* These hints can loop if [fixpoint_mono] and [fixpoint_proper] have
+   not been tried before, so we give them a high cost *)
+Hint Resolve fixpoint_unfold_subtype_l|100 : lrust_typing.
+Hint Resolve fixpoint_unfold_subtype_r|100 : lrust_typing.
+Hint Resolve fixpoint_unfold_eqtype_l|100 : lrust_typing.
+Hint Resolve fixpoint_unfold_eqtype_r|100 : lrust_typing.