dotnet/efcore · error · InvalidOperationException

Named default constraints cannot be used with TPC or entity

Error message

Named default constraints cannot be used with TPC or entity splitting if they result in non-unique constraint names. Constraint name: '{constraintNameCandidate}'.

What it means

Thrown by SharedTableConvention.TryUniquifyDefaultConstraint (SharedTableConvention.cs:766-770) when a property is mapped to more than one table (as in TPC inheritance or entity splitting) and the default constraint name has NO explicit configuration source (it's auto-generated/implicit). Since the constraint name must be unique per table but the implicit name is shared, EF cannot safely uniquify it. This is tracked as issue #27970 and is a known limitation.

Source

Thrown at src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs:768

    private static string? TryUniquifyDefaultConstraint(
        IConventionProperty property,
        string constraintName,
        string? schema,
        Dictionary<(string, string?), (IConventionProperty, StoreObjectIdentifier)> defaultConstraints,
        in StoreObjectIdentifier storeObject,
        int maxLength)
    {
        var mappedTables = property.GetMappedStoreObjects(StoreObjectType.Table);
        if (mappedTables.Count() > 1)
        {
            // For TPC and some entity splitting scenarios we end up with multiple tables having to define the constraint.
            // Since constraint name has to be unique, we can't keep the same name for all
            // Disabling this scenario until we have better way to configure the constraint name
            // see issue #27970
            if (property.GetDefaultConstraintNameConfigurationSource() == null)
            {
                throw new InvalidOperationException(
                    RelationalStrings.ImplicitDefaultNamesNotSupportedForTpcWhenNamesClash(constraintName));
            }

            throw new InvalidOperationException(
                RelationalStrings.ExplicitDefaultConstraintNamesNotSupportedForTpc(constraintName));
        }

        if (property.Builder.CanSetAnnotation(RelationalAnnotationNames.DefaultConstraintName, null))
        {
            constraintName = Uniquifier.Uniquify(constraintName, defaultConstraints, n => (n, schema), maxLength);
            property.Builder.HasAnnotation(RelationalAnnotationNames.DefaultConstraintName, constraintName);
            return constraintName;
        }

        return null;
    }

    private void UniquifyTriggerNames(

View on GitHub (pinned to dbf9771522)

Solutions

  1. Explicitly set a unique default constraint name per table using HasDefaultValue(value, defaultValueSql: null).HasDefaultValueConstraintName("DF_TableName_Col") for each mapped table.
  2. Remove the default value from properties involved in TPC/entity splitting, or set defaults at the database level outside EF.
  3. Switch from TPC to TPH or TPT if possible, where this limitation does not apply.

Example fix

// before: TPC with implicit default constraint names that clash
modelBuilder.Entity<Base>().UseTpcMappingStrategy();
modelBuilder.Entity<Base>().Property(b => b.Status).HasDefaultValue(0);

// after: explicitly name the default constraint uniquely per table
modelBuilder.Entity<DerivedA>().ToTable("DerivedA", t =>
    t.Property(b => b.Status).HasDefaultValue(0).HasDefaultValueConstraintName("DF_DerivedA_Status"));
modelBuilder.Entity<DerivedB>().ToTable("DerivedB", t =>
    t.Property(b => b.Status).HasDefaultValue(0).HasDefaultValueConstraintName("DF_DerivedB_Status"));
Defensive patterns

Strategy: validation

Validate before calling

// Detect TPC/entity-splitting properties with implicit default constraint names mapped to multiple tables.
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    foreach (var prop in et.GetDeclaredProperties())
    {
        if (prop.GetMappedStoreObjects(StoreObjectType.Table).Count() <= 1) continue;
        if (prop.GetDefaultValue() != null && prop.GetDefaultConstraintNameConfigurationSource() == null)
            Console.WriteLine($"Property {et.DisplayName()}.{prop.Name} maps to multiple tables with a default but no explicit constraint name — TPC limitation.");
    }
}

Prevention

When it happens

Trigger: Using TPC inheritance (UseTpcMapping) or entity splitting where an entity has a property with a default value (or computed default), the property maps to multiple tables, and the default constraint name was not explicitly set via HasDefaultValue(...).HasDefaultValueConstraintName("...").

Common situations: Switching from TPH/TPT to TPC with properties that have default values. Entity splitting with default values. EF auto-generates default constraint names that clash across the multiple tables in TPC.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/8373bde312764809. Report an issue: GitHub.