diff --git a/rfcs/recursive-type-unrestriction.md b/rfcs/recursive-type-unrestriction.md
new file mode 100644
index 00000000..dc739c58
--- /dev/null
+++ b/rfcs/recursive-type-unrestriction.md
@@ -0,0 +1,121 @@
+# Loosening the recursive type restriction
+
+## Summary
+
+Luau supports recursive type aliases, but with an important
+restriction: users can declare functions of recursive types, but *not*
+recursive type functions. This has problems with sophisticated uses of
+types, for example ones which mix recursive types and nested generics.
+This RFC proposes loosening this restriction.
+
+## Motivation
+
+Luau supports recursive type aliases, but with an important restriction:
+users can declare functions of recursive types, such as:
+```lua
+ type Tree = { data: a, children: {Tree} }
+```
+but *not* recursive type functions, such as:
+```lua
+ type TreeWithMap = { ..., map: (a -> b) -> Tree }
+
+```
+These examples cope up naturally in OO code bases with generic types.
+
+## Design
+
+*This section to be filled in once we decide which alternative to use*
+
+## Drawbacks
+
+*This section to be filled in once we decide which alternative to use*
+
+## Alternatives
+
+### Lazy recursive type instantiations
+
+The most permissive change would be to make recursive type
+instantiation lazy rather than strict. In this approach `T` would
+not be instantiated immediately, but only when the body is needed. In
+particular, during unification we can unify `T` with `T` by
+first trying to unify `U` and `V`, and only if that fails try to unify
+the instantiations.
+
+*Advantages*: this allows recursive types with infinite expansions like:
+```lua
+ type Foo = { ..., promises: {Foo>} }
+```
+
+### Lazy recursive type instantiations with a cache
+
+As above, but keep a cache for each type function.
+
+*Advantages*: reduces the size of the type graph.
+
+### Strict recursive type instantiations with a cache
+
+Rather than lazily instantiating type functions when they are used, we
+could carry on instantiating them when they are defined, and use a
+cache to reuse them. In particular, the cache would be populated when the
+recursive types are defined, and used when types are used recursively.
+
+For example:
+```
+type T = { foo: T? }
+```
+would result in cache entries:
+```
+T = { foo: T? }
+T = { foo: T? }
+T = { foo: T? }
+```
+This can result in exponential blowup, for example:
+```
+type T = { foo: T?, bar: T? }
+```
+would result in cache entries:
+```
+T = { foo: T?, bar: T? }
+T = { foo: T?, bar: T? }
+T = { foo: T?, bar: T? }
+T = { foo: T?, bar: T? }
+T = { foo: T?, bar: T? }
+T = { foo: T?, bar: T? }
+T = { foo: T?, bar: T? }
+```
+Applying this to a type function with N type variables results in more than 2^N
+types. Because of blowup, we would need a bound on cache size.
+
+This can also result in the cache being exhausted, for example:
+```
+type T = { foo: T>? }
+```
+results in an infinite type graph with cache:
+```
+T = { foo: T>? }
+T> = { foo: T>>? }
+T>> = { foo: T>>>? }
+...
+```
+
+*Advantages*: types are computed strictly, so we don't have to worry about lazy types
+producing unbounded type graphs during unification.
+
+### Strict recursive type instantiations with a cache and an occurrence check
+
+We can use occurrence checks to ensure there's no blowup. We can restrict
+a recursive use `T` in the definition of `T` so that either `UI` is `aI`
+or contains none of `a1...aN`. For example this bans
+```
+type T = { foo: T>? }
+```
+since `Promise` is not `a` but contains `a`, and bans
+```
+type T = { foo: T? }
+```
+since `a` is not `b`, but allows:
+```
+type T = { foo: T? }
+```
+
+*Advantages*: types are computed strictly, and may produce better error messages if the occurs check fails.