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

  1. Give the derived check constraint a distinct name so it does not collide with the base one.
  2. Make the derived constraint's SQL compatible with (or identical to) the base so AreCompatible passes.
  3. Remove the redundant derived declaration and let it inherit from the base.
  4. 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

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


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)