dotnet/efcore · error · InvalidOperationException

Entity type ' ' has a split mapping for ' ', but the…

Error message

Entity type '{entityType}' has a split mapping for '{storeObject}', but the primary key properties aren't fully mapped. Map all primary key properties to columns on '{storeObject}'.

What it means

Entity splitting spreads one entity across several tables via SplitToTable/SplitToView fragments. The relational model validator walks each fragment and resolves a column name for every property; if a PRIMARY KEY property resolves to no column on a fragment, it throws, because the fragment cannot link its rows back to the entity without the full key. All key columns must be present on every split fragment.

Solutions

  1. Ensure every primary key property has a column on the offending fragment: property.HasColumnName("Id", "ExtraFragmentName").
  2. Remove any table-specific override (.HasColumnName(null, fragment)) that is suppressing a key column on the fragment.
  3. If the fragment cannot carry the full key, drop the fragment and model the extra columns differently (owned type, one-to-one, or TPH).
  4. Verify the entity's key is not shadow/composite-with-unmapped-part that never reaches the fragment.

Example fix

// before
modelBuilder.Entity<Customer>()
    .SplitToTable("CustomerExtra", tb =>
    {
        tb.Property(c => c.Notes).HasColumnName("Notes");
        // Id not mapped -> [440]
    });

// after
modelBuilder.Entity<Customer>()
    .SplitToTable("CustomerExtra", tb =>
    {
        tb.Property(c => c.Id).HasColumnName("Id");
        tb.Property(c => c.Notes).HasColumnName("Notes");
    });
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on the model, verify every key property has a column on each split fragment.
foreach (var fragment in entityType.GetTableMappings().SelectMany(t => t.EntityTypeMappings).SelectMany(m => m.TableMappings is null ? Array.Empty<object>() : Array.Empty<object>())) { /* placeholder */ }

// Simpler: assert key coverage per fragment store object.
var fragments = entityType.GetFragmentMappings(); // or your mapping accessor
foreach (var fragment in entityType.GetMappingFragments())
{
    foreach (var keyProp in entityType.FindPrimaryKey()!.Properties)
    {
        if (keyProp.GetColumnName(fragment.StoreObject) is null)
            throw new InvalidOperationException($"Key property {keyProp.Name} is unmapped on fragment {fragment.StoreObject.DisplayName()}.");
    }
}

Type guard

// Guard before adding a split fragment.
static bool IsKeyFullyMappedOnFragment(IEntityType et, StoreObjectIdentifier store)
    => et.FindPrimaryKey()!.Properties.All(p => p.GetColumnName(store) is not null);

Prevention

When it happens

Trigger: Calling entityTypeBuilder.SplitToTable("Extra") (or SplitToView / a MappingFragment) and then unmapping or renaming a key property on that fragment, e.g. property.HasColumnName(null, "Extra") on an Id property, or a table-specific override that drops the key column. Also triggered when a key convention is suppressed so GetColumnName(fragment.StoreObject) returns null for a key property.

Common situations: Copying a SplitToTable block and forgetting to map the key; using table-specific column overrides (.HasColumnName(name, name: "Extra")) that accidentally exclude the PK; renaming fragments; upgrading EF and a previously-tolerated mapping now fails validation.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/bd285f933f93c72d. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2424

                {
                    throw new InvalidOperationException(
                        RelationalStrings.EntitySplittingUnmatchedMainTableSplitting(
                            entityType.DisplayName(),
                            fragment.StoreObject.DisplayName(),
                            foreignKey.PrincipalEntityType.DisplayName(),
                            principalMainFragment.DisplayName()));
                }
            }

            var propertiesFound = false;
            foreach (var property in entityType.GetProperties())
            {
                var columnName = property.GetColumnName(fragment.StoreObject);
                if (columnName == null)
                {
                    if (property.IsPrimaryKey())
                    {
                        throw new InvalidOperationException(
                            RelationalStrings.EntitySplittingMissingPrimaryKey(
                                entityType.DisplayName(), fragment.StoreObject.DisplayName()));
                    }

                    continue;
                }

                if (!property.IsPrimaryKey())
                {
                    propertiesFound = true;
                }
            }

            if (!propertiesFound)
            {
                throw new InvalidOperationException(
                    RelationalStrings.EntitySplittingMissingProperties(
                        entityType.DisplayName(), fragment.StoreObject.DisplayName()));

View on GitHub (pinned to 3a2006ef56)