Type.FullName returns null when the type is not generic type definition but contains generic paramters.
The rational behind this design is to ensure Type.FullName (if not null) can uniquely identify a type in an assembly; or given the string returned by Type.FullName, Type.GetType(string typeName) can return the original type back. It is hard to keep this invariant if !type.IsGenericTypeDefinition && type.ContainsGenericParameters.
For instance, suppose we have an assembly compiled with the following C# code:
typeof(G<>).FullName is "G`1", and we can round trip this type from Type.GetType("G`1"). But we can build more complicated generic types, such as G<S> (type G<> bound with the generic parameter from the method M<>); in order to identify such type with a string, a lot of extra information is need.
Below are some examples where Type.FullName returns null.