dotnet/efcore · error · InvalidOperationException

Entity type '{entityType}' has a split mapping, but it doesn

Error message

Entity type '{entityType}' has a split mapping, but it doesn't map any non-primary key property to the main store object. Keep at least one non-primary key property mapped to a column on '{storeObject}'.

What it means

After validating all fragments, ValidateMappingFragment runs ValidateMainMapping on the entity's MAIN store object (Table or View) to ensure the main object still carries at least one non-primary-key property. If splitting moved every non-key property OFF the main object, the main table holds only the key and EF throws EntitySplittingMissingPropertiesMainFragment.

Source

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

                }

                var columnName = property.GetColumnName(mainObject);
                if (columnName != null)
                {
                    propertyFound = true;

                    if (!nonSharedRequiredPropertyFound
                        && !property.IsNullable
                        && property.FindSharedStoreObjectRootProperty(mainObject) == null)
                    {
                        nonSharedRequiredPropertyFound = true;
                    }
                }
            }

            if (!propertyFound)
            {
                throw new InvalidOperationException(
                    RelationalStrings.EntitySplittingMissingPropertiesMainFragment(
                        entityType.DisplayName(), mainObject.DisplayName()));
            }

            if (!nonSharedRequiredPropertyFound)
            {
                var rowInternalFk = entityType.FindRowInternalForeignKeys(mainObject).First(fk => !fk.IsRequiredDependent);
                throw new InvalidOperationException(
                    RelationalStrings.EntitySplittingMissingRequiredPropertiesOptionalDependent(
                        entityType.DisplayName(), mainObject.DisplayName(),
                        $".Navigation(p => p.{rowInternalFk.PrincipalToDependent!.Name}).IsRequired()"));
            }

            return mainObject;
        }
    }

    /// <summary>

View on GitHub (pinned to dbf9771522)

Solutions

  1. Keep at least one non-key property mapped to the main store object: do not move it into a .SplitToTable fragment.
  2. Move a property back from a fragment to the main table by removing it from the SplitToTable lambda.
  3. If the entity genuinely has only a key plus split payloads, add a discriminator/rowversion or other non-key column to the main table.

Example fix

// before
modelBuilder.Entity<Customer>().ToTable("Customers")
    .SplitToTable("CustomerExtras", t =>
    {
        t.Property(c => c.Id).HasColumnName("CustomerId");
        t.Property(c => c.Name);  // moved off main
        t.Property(c => c.Email); // moved off main
    }); // main table now has only Id

// after
modelBuilder.Entity<Customer>().ToTable("Customers")
    .SplitToTable("CustomerExtras", t =>
    {
        t.Property(c => c.Id).HasColumnName("CustomerId");
        t.Property(c => c.Email); // keep Name on main table
    });
Defensive patterns

Strategy: validation

Validate before calling

bool MainObjectRetainsPayload(DbContext context)
{
    foreach (var et in context.Model.GetEntityTypes())
    {
        if (!et.GetTableMappingFragments().Any()) continue;
        var main = StoreObjectIdentifier.Create(et, StoreObjectType.Table);
        if (main is null) continue;
        bool any = et.GetProperties().Any(p => !p.IsPrimaryKey() && p.GetColumnName(main) is not null);
        if (!any) return false;
    }
    return true;
}

Try / catch

try { _ = context.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("split mapping", StringComparison.Ordinal) && ex.Message.Contains("main store object", StringComparison.Ordinal))
{
    throw new InvalidOperationException("The main table has no non-key property left after splitting. Keep at least one payload column on the main table.", ex);
}

Prevention

When it happens

Trigger: The entity has split fragments and, for the main Table/View StoreObjectIdentifier, no non-PK property has a column (propertyFound stays false). Happens when you split ALL non-key properties onto other fragments, leaving the main table empty of payload.

Common situations: Aggressively splitting a wide entity and forgetting to leave at least one frequently-used column on the main table; refactoring splits so every payload column moved to fragments.

Related errors


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