.NET
open generic type
programming
software development
C#

What exactly is an open generic type in .NET?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

An open generic type in .NET is a generic type that still has one or more unassigned type parameters. It describes a type pattern rather than a fully usable concrete type, which is why the concept matters most in reflection, dependency injection, and framework code rather than in ordinary day-to-day object creation.

Start With the Basic Contrast

Consider List<T> and List<int>.

  • 'List<T> is open because T has not been replaced with a concrete type.'
  • 'List<int> is closed because all generic parameters are fully specified.'

That difference explains why you can instantiate one and not the other.

csharp
1using System;
2using System.Collections.Generic;
3
4var values = new List<int>();
5Console.WriteLine(values.GetType());
6
7// You cannot do: new List<T>()

A closed generic type is ready to use. An open generic type is a definition or template.

Open Generic, Closed Generic, and Generic Type Definition

There are three related terms that people often mix together.

  • generic type definition: the original generic shape, such as Dictionary<TKey, TValue>
  • open generic type: any generic type that still contains unassigned type parameters
  • closed generic type: a generic type with all parameters filled in, such as Dictionary<string, int>

The generic type definition is always open, but not every open generic is the bare definition.

For example, a type can be partially constructed and still open.

csharp
1public class Pair<TFirst, TSecond>
2{
3}
4
5// Pair<,> is the generic type definition.
6// A partially specified form can still be open if a parameter remains unresolved.

In ordinary C# syntax you do not usually write partially open forms directly, but they appear through reflection and inside generic type composition.

Why Open Generics Cannot Be Instantiated

The runtime cannot create an instance of a type that still has unresolved type parameters, because it does not yet know the full field layout, method signatures, or type-specific operations.

That is why this works only after you supply the missing arguments.

csharp
1using System;
2using System.Collections.Generic;
3
4Type openType = typeof(List<>);
5Type closedType = openType.MakeGenericType(typeof(string));
6
7object instance = Activator.CreateInstance(closedType)!;
8Console.WriteLine(instance.GetType());

The open type is useful metadata. The closed type is what you can actually instantiate.

Reflection APIs That Matter

In reflection, the two most helpful properties are IsGenericTypeDefinition and ContainsGenericParameters.

csharp
1using System;
2using System.Collections.Generic;
3
4Type a = typeof(List<>);
5Type b = typeof(List<int>);
6
7Console.WriteLine(a.IsGenericTypeDefinition);      // True
8Console.WriteLine(a.ContainsGenericParameters);    // True
9
10Console.WriteLine(b.IsGenericTypeDefinition);      // False
11Console.WriteLine(b.ContainsGenericParameters);    // False

IsGenericTypeDefinition tells you whether the type is the original generic template itself.

ContainsGenericParameters tells you whether the type is still open in any way. That distinction matters because some types are not definitions but still contain unresolved generic parameters.

Why Frameworks Care About Open Generics

Open generics appear frequently in infrastructure code. Dependency injection containers, serializers, mappers, and ORMs often register or reason about services in open-generic form.

A common DI example is registering a generic repository once.

csharp
// Example concept:
// services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

That registration tells the container, "Whenever someone asks for IRepository<Customer>, build Repository<Customer>." The registration itself is open. The resolved service is closed.

This is one reason the concept matters even if your application code rarely touches reflection directly.

Common Pitfalls

The most common mistake is calling any generic type with angle brackets an "open generic" even when all arguments are already filled in.

Another mistake is assuming IsGenericTypeDefinition and ContainsGenericParameters mean the same thing. They are related, but they answer different questions.

A third issue is trying to instantiate an open generic type directly through reflection without first closing it with MakeGenericType.

Finally, do not confuse a generic method with a generic type. The same vocabulary appears in both places, but the runtime APIs are different.

Summary

  • An open generic type is a generic type that still has one or more unresolved type parameters.
  • 'List<> is open, while List<int> is closed.'
  • A generic type definition is the original template form of a generic type.
  • Open generics are useful for reflection, framework code, and DI container registration.
  • You cannot instantiate an open generic until you close it with concrete type arguments.
  • In reflection, IsGenericTypeDefinition and ContainsGenericParameters answer different but related questions.

Course illustration
Course illustration

All Rights Reserved.