Skip to main content

How to Resolve Error "CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list." in C#

The Compiler Error CS0449 is a syntax and logic error regarding Generic Type Constraints. The message reads: "The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list."

In C#, when you define constraints on a generic type T (using the where keyword), there is a strict hierarchy. Certain constraints are considered Primary Constraints. A generic parameter can define only one primary constraint (because a type cannot be both a reference type and a value type simultaneously), and that constraint must appear first in the list.

This guide explains the hierarchy of constraints and how to order them correctly.

Understanding Constraint Hierarchy

When defining where T : ..., the compiler enforces the following order:

  1. Primary Constraint (Optional, Max 1):
    • class (Reference type)
    • struct (Value type)
    • unmanaged (Unmanaged value type)
    • notnull (Non-nullable type)
    • default (Overridden context)
    • Or a specific Base Class name.
  2. Secondary Constraints (Optional, Multiple):
    • Interfaces (e.g., IEnumerable, IDisposable).
  3. Constructor Constraint (Optional, Max 1):
    • new() (Must be absolutely last).

CS0449 is triggered if you violate rule #1 by combining two items from that list or placing them after items from list #2.

Scenario 1: Combining Mutually Exclusive Constraints

You cannot require a type T to be both a Value Type (struct) and a Reference Type (class). This is a logical impossibility.

Example of error

public class DataStore<T> 
// ⛔️ Error CS0449: You cannot combine 'class' and 'struct'.
// A type cannot be stored on the Heap (class) AND strictly on the Stack (struct).
where T : class, struct
{
}

Solution: Choose One

Determine the nature of the data you want to support.

// ✅ Correct: Accepts only Reference Types
public class ReferenceStore<T> where T : class { }

// ✅ Correct: Accepts only Value Types
public class ValueStore<T> where T : struct { }
note

unmanaged implies struct: Using where T : unmanaged automatically implies it is a struct. You do not need (and cannot use) both. Use where T : unmanaged.

Scenario 2: Incorrect Ordering

Even if you pick only one primary constraint, it must be the very first item in the list. If you place an Interface constraint before the primary constraint, the compiler raises CS0449.

Example of error

using System;

public class Processor<T>
// ⛔️ Error CS0449: The 'class' constraint must be specified first.
where T : IDisposable, class
{
}

Solution: Reorder the List

Move class, struct, or notnull to the front.

using System;

public class Processor<T>
// ✅ Correct: Primary constraint first, Interfaces second.
where T : class, IDisposable
{
}

Scenario 3: Duplication

Listing the same constraint twice provides no value and is flagged as an error.

Example of error

public class Repository<T>
// ⛔️ Error CS0449: 'class' is duplicated.
where T : class, class
{
}

Solution: Remove Duplicates

Simply delete the redundant keyword.

public class Repository<T>
// ✅ Correct
where T : class
{
}

Conclusion

CS0449 enforces the grammar of Generic Constraints.

  1. Pick One Primary: You can have class, struct, notnull, OR unmanaged. Never two.
  2. Put it First: The primary constraint must appear before any Interface names or the new() constraint.
  3. Don't Repeat: Ensure you haven't typed the same constraint twice.