dotnet/efcore · error · InvalidOperationException
The check constraint '{checkConstraint}' cannot be added to
Error message
The check constraint '{checkConstraint}' cannot be added to the entity type '{entityType}' because another check constraint with the same name already exists on entity type '{conflictingEntityType}'. What it means
Thrown by CheckConstraintConvention.ProcessEntityTypeBaseTypeChanged (CheckConstraintConvention.cs:113-117) when setting a base type creates a conflict: a derived entity type has a check constraint with the same name as one on the new base type, they are incompatible (AreCompatible returns false), and all three configuration sources — the base type's check constraint, the entity's base-type setting, and the derived check constraint — are all ConfigurationSource.Explicit. EF cannot silently resolve an explicit-vs-explicit conflict.
Source
Thrown at src/EFCore.Relational/Metadata/Conventions/CheckConstraintConvention.cs:113
{
var entityType = entityTypeBuilder.Metadata;
if (newBaseType != null)
{
var configurationSource = entityType.GetBaseTypeConfigurationSource();
var baseCheckConstraints = newBaseType.GetCheckConstraints().ToDictionary(c => c.ModelName);
List<IConventionCheckConstraint>? checkConstraintsToBeDetached = null;
List<IConventionCheckConstraint>? checkConstraintsToBeRemoved = null;
foreach (var checkConstraint in entityType.GetDerivedTypesInclusive().SelectMany(et => et.GetDeclaredCheckConstraints()))
{
if (baseCheckConstraints.TryGetValue(checkConstraint.ModelName, out var baseCheckConstraint)
&& baseCheckConstraint.GetConfigurationSource().Overrides(checkConstraint.GetConfigurationSource())
&& !AreCompatible(checkConstraint, baseCheckConstraint))
{
if (baseCheckConstraint.GetConfigurationSource() == ConfigurationSource.Explicit
&& configurationSource == ConfigurationSource.Explicit
&& checkConstraint.GetConfigurationSource() == ConfigurationSource.Explicit)
{
throw new InvalidOperationException(
RelationalStrings.DuplicateCheckConstraint(
checkConstraint.ModelName,
checkConstraint.EntityType.DisplayName(),
baseCheckConstraint.EntityType.DisplayName()));
}
checkConstraintsToBeRemoved ??= [];
checkConstraintsToBeRemoved.Add(checkConstraint);
continue;
}
if (baseCheckConstraint != null)
{
checkConstraintsToBeDetached ??= [];
checkConstraintsToBeDetached.Add(checkConstraint);
}View on GitHub (pinned to dbf9771522)
Solutions
- Rename one of the conflicting check constraints so the names are unique across the hierarchy.
- Make the check constraint SQL identical on both types so AreCompatible returns true.
- Remove the check constraint from the derived type and keep it only on the base type.
- Lower the configuration source of one constraint below Explicit (e.g., via model configuration) so the convention can auto-resolve.
Example fix
// before: same name, incompatible SQL, both explicit
modelBuilder.Entity<Base>().ToTable(t => t.HasCheckConstraint("CK_Range", "Value > 0"));
modelBuilder.Entity<Derived>().HasBaseType<Base>()
.ToTable(t => t.HasCheckConstraint("CK_Range", "Value > 100")); // throws
// after: unique names
modelBuilder.Entity<Base>().ToTable(t => t.HasCheckConstraint("CK_Base_Range", "Value > 0"));
modelBuilder.Entity<Derived>().HasBaseType<Base>()
.ToTable(t => t.HasCheckConstraint("CK_Derived_Range", "Value > 100")); Defensive patterns
Strategy: validation
Validate before calling
// Before setting base type, check for duplicate check constraint names.
var baseNames = baseEntityType.GetCheckConstraints().Select(c => c.ModelName).ToHashSet();
foreach (var cc in derivedEntityType.GetDerivedTypesInclusive().SelectMany(e => e.GetDeclaredCheckConstraints()))
{
if (baseNames.Contains(cc.ModelName))
Console.WriteLine($"Check constraint '{cc.ModelName}' on {cc.EntityType.DisplayName()} conflicts with base type.");
} Prevention
- Use a naming convention that prefixes check constraint names with the entity type name to avoid collisions.
- When introducing inheritance, audit check constraints on all types for name collisions.
- Run a model validation test after adding HasBaseType to catch conflicts early.
When it happens
Trigger: Defining an inheritance hierarchy (setting HasBaseType) where both the base and derived entity types explicitly declare a check constraint with the same name but different SQL. E.g., base has .ToTable(t => t.HasCheckConstraint("CK_Range", "Col > 0")) and derived has HasCheckConstraint("CK_Range", "Col > 10").
Common situations: Adding inheritance to existing entity types that independently defined check constraints with the same name. Copy-pasting check constraint configuration across types that later become part of a hierarchy. Refactoring flat types into an inheritance hierarchy.
Related errors
- An Azure Cosmos DB container name is defined on entity type
- Cosmos automatic-indexing configuration was set on entity ty
- A partition key is defined on entity type '{entityType}', wh
- 'HasDiscriminatorInJsonId' or 'HasRootDiscriminatorInJsonId'
- 'HasShadowId' was called on a non-root entity type '{entityT
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/1800a61a7bdb050b.
Report an issue: GitHub.