dotnet/efcore · error · InvalidOperationException

The foreign keys {foreignKeyProperties1} on '{entityType1}'

Error message

The foreign keys {foreignKeyProperties1} on '{entityType1}' and {foreignKeyProperties2} on '{entityType2}' are both mapped to '{table}.{foreignKeyName}', but referencing different principal tables ('{principalTable1}' and '{principalTable2}').

What it means

Thrown by AreCompatible when two foreign keys share a name and are declared on the same dependent table, but reference different principal tables. A single database FK constraint can only point at one principal table, so EF rejects the ambiguous mapping.

Source

Thrown at src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs:67

                        duplicateForeignKey.DeclaringEntityType.DisplayName(),
                        principalTable.HasValue
                            ? foreignKey.GetConstraintName(storeObject, principalTable.Value)
                            : foreignKey.GetDefaultName(),
                        foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(),
                        duplicateForeignKey.DeclaringEntityType.GetSchemaQualifiedTableName()))
                : false;
        }

        if (principalTable is null
            || duplicatePrincipalTable is null
            || principalTable != duplicatePrincipalTable
            || foreignKey.PrincipalKey.Properties.GetColumnNames(principalTable.Value)
                is not { } principalColumns
            || duplicateForeignKey.PrincipalKey.Properties.GetColumnNames(principalTable.Value)
                is not { } duplicatePrincipalColumns)
        {
            return shouldThrow
                ? throw new InvalidOperationException(
                    RelationalStrings.DuplicateForeignKeyPrincipalTableMismatch(
                        foreignKey.Properties.Format(),
                        foreignKey.DeclaringEntityType.DisplayName(),
                        duplicateForeignKey.Properties.Format(),
                        duplicateForeignKey.DeclaringEntityType.DisplayName(),
                        foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(),
                        principalTable.HasValue
                            ? foreignKey.GetConstraintName(storeObject, principalTable.Value)
                            : foreignKey.GetDefaultName(),
                        principalType.GetSchemaQualifiedTableName(),
                        duplicatePrincipalType.GetSchemaQualifiedTableName()))
                : false;
        }

        if (!columnNames.SequenceEqual(duplicateColumnNames))
        {
            return shouldThrow
                ? throw new InvalidOperationException(

View on GitHub (pinned to dbf9771522)

Solutions

  1. Disambiguate the constraint names with explicit HasConstraintName so each points to its own principal cleanly.
  2. Reconcile the principal tables: if both FKs should target the same principal, fix the principal mapping.
  3. Split the dependent entity types onto separate tables if they genuinely reference different principals.
  4. Verify ToTable mapping for both principal entity types is what you intended.

Example fix

// before (OrderDetail shares table; FKs to Order vs Invoice, same constraint name)
modelBuilder.Entity<OrderDetail>().HasOne(d => d.Order)
    .WithMany().HasForeignKey(d => d.OrderId).HasConstraintName("FK_Detail_Principal");
modelBuilder.Entity<OrderDetail>().HasOne(d => d.Invoice)
    .WithMany().HasForeignKey(d => d.InvoiceId).HasConstraintName("FK_Detail_Principal");

// after
modelBuilder.Entity<OrderDetail>().HasOne(d => d.Order)
    .WithMany().HasForeignKey(d => d.OrderId).HasConstraintName("FK_Detail_Order");
modelBuilder.Entity<OrderDetail>().HasOne(d => d.Invoice)
    .WithMany().HasForeignKey(d => d.InvoiceId).HasConstraintName("FK_Detail_Invoice");
Defensive patterns

Strategy: validation

Validate before calling

// Verify FKs sharing a name also share the principal table
foreach (var g in modelBuilder.Model.GetEntityTypes().SelectMany(t => t.GetForeignKeys())
             .GroupBy(fk => fk.GetConstraintName()))
{
    var principalTables = g.Select(fk => fk.PrincipalEntityType.GetSchemaQualifiedTableName()).Distinct();
    if (principalTables.Count() > 1)
        throw new InvalidOperationException($"FK {g.Key} targets multiple principal tables.");
}

Prevention

When it happens

Trigger: Two FKs on entity types sharing a dependent table resolve to one constraint name, but their PrincipalEntityType maps to a different principal table. Common in TPH/table-splitting where dependent types share a row but point at different principals.

Common situations: Table-splitting or TPH where one shared table has FKs to two different principal tables but the constraint names collide. Refactoring a principal entity to a different table after FK config was set.

Related errors


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