dotnet/efcore · error · InvalidOperationException
The check constraint
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
CheckConstraintConvention.ProcessEntityTypeBaseTypeChanged runs when an entity is assigned a base type. It reconciles check constraints declared on the entity/derived types with those inherited from the base. If a derived type declares a check constraint whose ModelName matches a base one, the base has Explicit configuration source, the base-type change is Explicit, the derived is Explicit, AND they are incompatible, the convention cannot silently resolve it and throws DuplicateCheckConstraint.
Solutions
- Give the derived check constraint a distinct name so it does not collide with the base one.
- Make the derived constraint's SQL compatible with (or identical to) the base so AreCompatible passes.
- Remove the redundant derived declaration and let it inherit from the base.
- Lower one of the configuration sources below Explicit (data annotation / convention) so the convention can silently remove instead of throwing.
Example fix
// before — same-named, incompatible check constraints on base and derived, both explicit -> [457]
modelBuilder.Entity<Person>().ToTable("People")
.HasCheckConstraint("CK_Age", "Age > 0");
modelBuilder.Entity<Employee>().HasBaseType<Person>()
.HasCheckConstraint("CK_Age", "Age >= 18");
// after — unique name on the derived constraint (or align the SQL)
modelBuilder.Entity<Person>().ToTable("People")
.HasCheckConstraint("CK_Age_Positive", "Age > 0");
modelBuilder.Entity<Employee>().HasBaseType<Person>()
.HasCheckConstraint("CK_Age_Adult", "Age >= 18"); Defensive patterns
Strategy: validation
Validate before calling
// Before assigning a base type, detect same-named check constraints that are incompatible.
static IEnumerable<string> ConflictingCheckConstraintNames(IEntityType derived, IEntityType baseType)
{
var baseCks = baseType.GetCheckConstraints().ToDictionary(c => c.ModelName);
foreach (var c in derived.GetDerivedTypesInclusive().SelectMany(et => et.GetDeclaredCheckConstraints()))
if (baseCks.TryGetValue(c.ModelName, out var b) && !CheckConstraintsCompatible(c, b))
yield return c.ModelName;
} Prevention
- Use distinct check-constraint names across base and derived types.
- Align derived constraint SQL with the base when names must match.
- Run a model-build test after introducing inheritance to surface constraint collisions.
When it happens
Trigger: Setting a base type explicitly (.HasBaseType<Base>()) on an entity that already declares a check constraint with the same name (ModelName) as one on the base, where both were configured via the Fluent API (Explicit) and their SQL/sql differs (AreCompatible returns false).
Common situations: Refactoring an entity into a hierarchy; copy-pasting check-constraint config between base and derived; renaming constraints such that ModelNames collide; introducing inheritance after the fact.
Related errors
- An Azure Cosmos DB container name is defined on entity type
- Both ' ' and ' ' are explicitly mapped to the stored…
- Both ' ' and ' ' are mapped to the table ' '. All the…
- Both ' ' and ' ' are mapped to the stored procedure ' '…
- Both ' ' and ' ' are mapped to the view ' '. All the entity…
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/1800a61a7bdb050b.
Report an issue: GitHub.
Appendix: 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 3a2006ef56)