diff --git a/client/Infer.ml b/client/Infer.ml
index 0e57b3d314cbeb14e7619eae9f29155f75d08de1..50791d517aaf88c61d9276a02244c9e47c79c8c4 100644
--- a/client/Infer.ml
+++ b/client/Infer.ml
@@ -355,14 +355,18 @@ let hastype (typedecl_env : ML.datatype_env) (t : ML.term) (w : variable) : F.no
 
       (* Generalization. *)
     | ML.Let (loc, rec_, x, t, u) ->
-
-        begin match rec_ with
-        | ML.Non_recursive -> ()
-        | ML.Recursive -> raise (Error (loc, Unsupported "let rec"))
-        end;
-
+      let hastype_def x t v =
+        match rec_ with
+        | ML.Non_recursive -> hastype t v
+        | ML.Recursive ->
+          (* For recursive definitions [let rec x = t], we bind the
+             variable [x] to the monomorphic expected type of [t] when
+             inferring the type of [t] itself. *)
+          def (X.Var x) v (hastype t v)
+      in
       (* Construct a ``let'' constraint. *)
-      let+ (a, (b, ty), t', u') = let1 (X.Var x) (hastype t) (hastype u w) in
+      let+ (a, (b, ty), t', u') =
+        let1 (X.Var x) (hastype_def x t) (hastype u w) in
       (* [a] are the type variables that we must bind (via Lambda abstractions)
          while type-checking [t]. [(b, _)] is the type scheme that [x] must
          receive while type-checking [u]. Its quantifiers [b] are guaranteed to
@@ -372,7 +376,43 @@ let hastype (typedecl_env : ML.datatype_env) (t : ML.term) (w : variable) : F.no
          produced. *)
       let sch tyvars =
         List.fold_right (fun alpha sch -> F.TyForall (alpha, sch)) tyvars ty in
-      F.Let (loc, F.Non_recursive, x, sch a, F.ftyabs ~loc a t',
+      let rec_ = match rec_ with
+        | ML.Recursive -> F.Recursive
+        | ML.Non_recursive -> F.Non_recursive
+      in
+      let t'' = match rec_ with
+        | F.Non_recursive -> t'
+        | F.Recursive ->
+          (* For recursive definitions, the defined variable is used monomorphically
+             within the definition, so we must instantiate the type scheme.
+
+             Consider for example:
+               let rec loop x = loop x
+             Which gets inferred at type ([a] [b] a -> b).
+
+             We do not want to get
+
+               let rec (loop : [a] [b] a -> b) =
+                 Fun a b ->
+                   fun (x : a) -> loop x
+
+             which is ill-typed: the recursive occurrence of 'loop' in its body
+             is applied as a monomorphic function, but it is bound to the polymorphic
+             (loop : [a] [b] a -> b).
+
+             Instead we elaborate into the following:
+
+               let rec (loop : [a] [b] a -> b) =
+                 Fun a b ->
+                   let loop = loop [a] [b] in
+                   fun (x : a) -> loop x
+          *)
+          flet ~loc (x, ty,
+                     F.ftyapp ~loc (F.Var (loc, x)) (List.map (fun v -> F.TyVar v) a),
+                     t')
+      in
+      F.Let (loc, rec_, x, sch a,
+             F.ftyabs ~loc a t'',
              flet ~loc (x, sch b, coerce ~loc a b (F.Var (loc, x)),
                         u'))
 
diff --git a/client/test/RandomML.ml b/client/test/RandomML.ml
index c1f4f0040bae230be610997e5c7ad29e8ebf7d93..90a666326a53a7a827ec8c68cb5607e2128546d7 100644
--- a/client/test/RandomML.ml
+++ b/client/test/RandomML.ml
@@ -37,9 +37,7 @@ let let_ self k n =
   let* rec_ =
     frequency [
       3, pure ML.Non_recursive;
-      (* we disable 'let rec' generation for tnow,
-         as the type-checker does not suport it. *)
-      (* 1, pure ML.Recursive; *)
+      1, pure ML.Recursive;
     ] in
   let+ x, t1, t2 =
     let inner_k = match rec_ with
diff --git a/client/test/suite.t/letrec-add.midml b/client/test/suite.t/letrec-add.midml
new file mode 100644
index 0000000000000000000000000000000000000000..905d284579a5c3c4fb6923ee238b0f8502ceaa02
--- /dev/null
+++ b/client/test/suite.t/letrec-add.midml
@@ -0,0 +1,11 @@
+#use nat.midml
+
+(* toplevel recursion is currently not supported,
+   so we wrap a "let rec .. in .." *)
+let add =
+  let rec add = fun m n ->
+    match m with
+    | Zero -> n
+    | Succ m1 -> add m1 (Succ n)
+    end
+  in add
\ No newline at end of file
diff --git a/client/test/suite.t/run.t b/client/test/suite.t/run.t
index 653f6586ad3c78bd75ccf19e4418009deb8a5e5f..6894a99669f3b28c74eda77441b4c4b9145317cb 100644
--- a/client/test/suite.t/run.t
+++ b/client/test/suite.t/run.t
@@ -311,7 +311,36 @@ Mutual recursion is not yet supported.
 
 Polymorphic recursion is not yet supported.
 
-A simple let-rec function: List.length
+A simple let-rec function: addition of natural numbers.
+
+  $ cat letrec-add.midml
+  #use nat.midml
+  
+  (* toplevel recursion is currently not supported,
+     so we wrap a "let rec .. in .." *)
+  let add =
+    let rec add = fun m n ->
+      match m with
+      | Zero -> n
+      | Succ m1 -> add m1 (Succ n)
+      end
+    in add
+
+  $ midml letrec-add.midml
+  Type inference and translation to System F...
+  Formatting the System F term...
+  Pretty-printing the System F term...
+  let rec (add : nat  -> nat  -> nat ) =
+    fun (m : nat ) (n : nat ) ->
+      match<nat > m with
+      | Zero<nat > () -> n
+      | Succ<nat > m1 -> add m1 (Succ<nat > n)
+      end
+  in add
+  Converting the System F term to de Bruijn style...
+  Type-checking the System F term...
+
+A classic let-rec function: List.length
 
   $ cat letrec-list-length.midml
   #use nat.midml
@@ -329,8 +358,20 @@ A simple let-rec function: List.length
 
   $ midml letrec-list-length.midml
   Type inference and translation to System F...
-  File "test", line 7, characters 2-127:
-  Type inference does not yet support "let rec".
+  Formatting the System F term...
+  Pretty-printing the System F term...
+  FUN a0 ->
+    let rec (length : [a1] list a1 -> nat ) =
+      FUN a2 ->
+        let (length : list a2 -> nat ) = length [a2] in
+        fun (xs : list a2) ->
+          match<nat > xs with
+          | Nil<list a2> () -> Zero<nat > ()
+          | Cons<list a2> (_, rest) -> Succ<nat > (length rest)
+          end
+    in length [a0]
+  Converting the System F term to de Bruijn style...
+  Type-checking the System F term...
 
 Using recursion to define (loop : 'a -> 'b)
 
@@ -342,8 +383,15 @@ Using recursion to define (loop : 'a -> 'b)
 
   $ midml letrec-loop.midml
   Type inference and translation to System F...
-  File "test", line 3, characters 2-42:
-  Type inference does not yet support "let rec".
+  Formatting the System F term...
+  Pretty-printing the System F term...
+  FUN a0 a1 ->
+    let rec (loop : [a2] [a3] a3 -> a2) =
+      FUN a4 a5 ->
+        let (loop : a5 -> a4) = loop [a4] [a5] in fun (x : a5) -> loop x
+    in loop [a1] [a0]
+  Converting the System F term to de Bruijn style...
+  Type-checking the System F term...
 
 # Rigid, flexible variables.