dotnet/efcore · error · InvalidOperationException
Entity type '{entityType}' has a split mapping and is an opt
Error message
Entity type '{entityType}' has a split mapping and is an optional dependent sharing a store object, but it doesn't map any required non-shared property to the main store object. Keep at least one required non-shared property mapped to a column on '{storeObject}' or mark '{entityType}' as a required dependent by calling '{requiredDependentConfig}'. What it means
Thrown during model validation when an entity type uses entity splitting (maps to multiple table fragments) and is also an optional dependent (its row-internal foreign key is not required). EF requires that at least one non-shared, non-nullable property be mapped to the main store object, so a row can be distinguished from 'all nulls'. Without it EF cannot determine whether the optional dependent row exists. The validator at RelationalModelValidator.cs:2466-2507 iterates all non-PK properties and checks IsNullable and FindSharedStoreObjectRootProperty against the main table.
Source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2503
&& !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>
/// Validates a table-specific property override for a property.
/// </summary>
/// <param name="property">The property to validate.</param>
/// <param name="propertyOverride">The property override to validate.</param>
/// <param name="logger">The logger to use.</param>
protected virtual void ValidatePropertyOverride(
IProperty property,
IReadOnlyRelationalPropertyOverrides propertyOverride,View on GitHub (pinned to dbf9771522)
Solutions
- Make at least one non-shared property non-nullable and map it to the main table (configure it as required).
- Call .Navigation(p => p.YourNavigation).IsRequired() on the owning entity to mark the dependent as required, so EF doesn't need the sentinel column.
- Move the split fragment mapping so that at least one required property stays on the main table rather than on the split fragment.
- Add a non-nullable discriminator or sentinel property to the main table.
Example fix
// before: all properties on main table are nullable or shared
modelBuilder.Entity<Order>()
.OwnsOne(o => o.Details, db =>
{
db.ToTable("OrderDetailsSplit");
db.Property(d => d.Notes).HasColumnName("DetailsNotes"); // only nullable props remain on main
});
// after: mark the owned navigation as required
modelBuilder.Entity<Order>()
.OwnsOne(o => o.Details, db =>
{
db.ToTable("OrderDetailsSplit");
})
.Navigation(o => o.Details)
.IsRequired(); Defensive patterns
Strategy: validation
Validate before calling
// Before finalizing the model, check that each split-mapped optional dependent has a required non-shared property on the main table.
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var fragments = entityType.GetMappingFragments(StoreObjectType.Table).ToList();
if (fragments.Count == 0) continue;
var mainObj = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table).GetValueOrDefault();
var hasNonRequiredFk = entityType.FindRowInternalForeignKeys(mainObj).Any(fk => !fk.IsRequiredDependent);
if (!hasNonRequiredFk) continue;
var hasRequiredNonShared = entityType.GetProperties()
.Where(p => !p.IsPrimaryKey())
.Any(p => p.GetColumnName(mainObj) != null && !p.IsNullable
&& p.FindSharedStoreObjectRootProperty(mainObj) == null);
if (!hasRequiredNonShared)
Console.WriteLine($"WARN: {entityType.DisplayName()} needs a required property on {mainObj.DisplayName()} or IsRequired() on its navigation.");
} Prevention
- When using entity splitting with owned types, always call .Navigation(...).IsRequired() or ensure at least one non-nullable non-FK property stays on the main table.
- Review split fragment mappings to ensure the main table retains a sentinel column for optional dependents.
- Run model validation early in unit tests with context.Model.FinalizeModel() to catch this before runtime.
When it happens
Trigger: Called by ValidateMainMapping when entityType.GetMappingFragments() returns table or view fragments AND entityType.FindRowInternalForeignKeys(mainObject) contains an FK where IsRequiredDependent is false, AND no non-PK property satisfies (GetColumnName(mainObject) != null && !IsNullable && FindSharedStoreObjectRootProperty(mainObject) == null).
Common situations: Using owned entity types with entity splitting (SplitToTable) where all non-key properties on the main table are either nullable, shared (FK columns from the principal), or moved to a split fragment. Common when migrating from TPH/owned types to splitting and accidentally making all columns nullable.
Related errors
- Entity type '{entityType}' has a split mapping for '{storeOb
- The entity type '{entityType}' is owned by the entity type '
- The entity type '{entityType}' is mapped to the container '{
- The index over properties '{properties}' is declared on owne
- Entity type '{entityType}' is an optional dependent using ta
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/a806de288a1a16b9.
Report an issue: GitHub.