dotnet/efcore · error · InvalidOperationException
The entity type '{ownerType}' is not mapped, so by default t
Error message
The entity type '{ownerType}' is not mapped, so by default the owned type '{navigation}.{ownedType}' will also be unmapped. If this is intended explicitly map the owned type to 'null', otherwise map it to a named '{storeObjectType}'. What it means
Raised by ValidateNonTphMapping when an entity type in a TPT/TPC hierarchy is itself unmapped to a given store object type, yet one of its owned navigations is also unmapped by default and at least one derived type in the hierarchy IS mapped to that store object type. EF cannot silently drop the owned entity from the hierarchy, so it asks you to be explicit: either confirm the owned type should be unmapped, or give it a concrete store object.
Source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2225
private static void ValidateNonTphMapping(IEntityType rootEntityType, StoreObjectType storeObjectType)
{
var isTpc = rootEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy;
var derivedTypes = new Dictionary<StoreObjectIdentifier, IEntityType>();
foreach (var entityType in rootEntityType.GetDerivedTypesInclusive())
{
var storeObject = StoreObjectIdentifier.Create(entityType, storeObjectType);
if (storeObject == null)
{
var unmappedOwnedType = entityType.GetReferencingForeignKeys()
.Where(fk => fk.IsOwnership)
.Select(fk => fk.DeclaringEntityType)
.FirstOrDefault(owned => StoreObjectIdentifier.Create(owned, storeObjectType) == null
&& ((IConventionEntityType)owned).GetStoreObjectConfigurationSource(storeObjectType) == null
&& !owned.IsMappedToJson());
if (unmappedOwnedType != null
&& entityType.GetDerivedTypes().Any(derived => StoreObjectIdentifier.Create(derived, storeObjectType) != null))
{
throw new InvalidOperationException(
RelationalStrings.UnmappedNonTPHOwner(
entityType.DisplayName(),
unmappedOwnedType.FindOwnership()!.PrincipalToDependent?.Name,
unmappedOwnedType.DisplayName(),
storeObjectType));
}
continue;
}
if (derivedTypes.TryGetValue(storeObject.Value, out var otherType))
{
switch (storeObjectType)
{
case StoreObjectType.Table:
throw new InvalidOperationException(
RelationalStrings.NonTphTableClash(
entityType.DisplayName(), otherType.DisplayName(), storeObject.Value.DisplayName()));View on GitHub (pinned to dbf9771522)
Solutions
- Explicitly map the owned navigation to null to confirm it is intentionally unmapped, or to a named store object: modelBuilder.Entity<Owner>().OwnsOne(o => o.Address, a => a.ToTable("Addresses")).
- Map the unmapped owner entity type to a store object of the same type (ToTable / ToView / ToFunction) so the hierarchy is fully represented.
- Remove the derived-type mapping that left the hierarchy half-mapped if only the base should be persisted.
Example fix
// before
modelBuilder.Entity<Owner>().OwnsOne(o => o.Address); // base Owner not mapped, derived types mapped
// after
modelBuilder.Entity<Owner>().OwnsOne(o => o.Address, a => a.ToTable("Addresses")); Defensive patterns
Strategy: validation
Validate before calling
bool NoUnmappedOwnedInNonTphHierarchy(DbContext context)
{
foreach (var root in context.Model.GetEntityTypes()
.Where(e => e.BaseType == null && e.GetMappingStrategy() is "TPT" or "TPC"))
{
foreach (var et in root.GetDerivedTypesInclusive())
{
var owned = et.GetReferencingForeignKeys()
.Where(fk => fk.IsOwnership)
.Select(fk => fk.DeclaringEntityType)
.FirstOrDefault(o => StoreObjectIdentifier.Create(o, StoreObjectType.Table) == null
&& ((IConventionEntityType)o).GetStoreObjectConfigurationSource(StoreObjectType.Table) == null
&& !o.IsMappedToJson());
if (owned != null && et.GetDerivedTypes().Any(d => StoreObjectIdentifier.Create(d, StoreObjectType.Table) != null))
return false;
}
}
return true;
} Try / catch
try { _ = context.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("not mapped", StringComparison.Ordinal) && ex.Message.Contains("owned type", StringComparison.Ordinal))
{
throw new InvalidOperationException("An owned navigation is unmapped in a non-TPH hierarchy. Explicitly map it with ToTable/ToView or to null.", ex);
} Prevention
- Always give owned navigations an explicit ToTable/ToView in TPT/TPC hierarchies.
- Map the whole hierarchy (base + derived) consistently to the same store object type.
- Add a model validation unit test that exercises context.Model after configuration.
When it happens
Trigger: Triggered when StoreObjectIdentifier.Create(entityType, storeObjectType) returns null for a non-TPH root, an ownership declared on it has no store object configuration source, the owned type is not JSON-mapped, and GetDerivedTypes().Any(derived mapped to that storeObjectType) is true. Typically appears when you map only some derived types to a table/view and leave the owner (and its owned navigation) unmapped.
Common situations: Mixing TPT table mapping with an owned entity on the base where the base has no ToTable; mapping derived types to views while leaving the base unmapped; partial hierarchy mappings introduced by scaffolded or hand-edited configurations.
Related errors
- The short name for '{entityType1}' is '{discriminatorValue}'
- Both '{entityType}' and '{otherEntityType}' are mapped to th
- Both '{entityType}' and '{otherEntityType}' are mapped to th
- Both '{entityType}' and '{otherEntityType}' are mapped to th
- The derived entity type '{entityType}' was configured with t
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/2a71fa361ab12441.
Report an issue: GitHub.