{"record":{"id":"fa2d6159910ad45f","repo":"dotnet/efcore","slug":"property-property-on-entity-type-entitytype","errorCode":null,"errorMessage":"Property '{property}' on entity type '{entityType}' is mapped without a CLR property. 'UseChangeTrackingProxies' requires all entity types to be public, unsealed, have virtual properties, and have a public or protected constructor. 'UseLazyLoadingProxies' requires only the navigation properties be virtual.","messagePattern":"Property '(.+?)' on entity type '(.+?)' is mapped without a CLR property\\. 'UseChangeTrackingProxies' requires all entity types to be public, unsealed, have virtual properties, and have a public or protected constructor\\. 'UseLazyLoadingProxies' requires only the navigation properties be virtual\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Proxies/Proxies/Internal/ProxyBindingRewriter.cs","lineNumber":86,"sourceCode":"                {\n                    continue;\n                }\n\n                if (clrType.IsSealed)\n                {\n                    throw new InvalidOperationException(ProxiesStrings.ItsASeal(entityType.DisplayName()));\n                }\n\n                foreach (var navigationBase in entityType.GetDeclaredNavigations()\n                             .Concat<IConventionNavigationBase>(entityType.GetDeclaredSkipNavigations()))\n                {\n                    if (!navigationBase.IsShadowProperty())\n                    {\n                        if (_options.UseChangeTrackingProxies)\n                        {\n                            if (navigationBase.PropertyInfo == null)\n                            {\n                                throw new InvalidOperationException(\n                                    ProxiesStrings.FieldProperty(navigationBase.Name, entityType.DisplayName()));\n                            }\n\n                            if (navigationBase.PropertyInfo.SetMethod?.IsReallyVirtual() == false)\n                            {\n                                throw new InvalidOperationException(\n                                    ProxiesStrings.NonVirtualProperty(navigationBase.Name, entityType.DisplayName()));\n                            }\n                        }\n\n                        if (_options.UseLazyLoadingProxies\n                            && navigationBase.LazyLoadingEnabled)\n                        {\n                            if (navigationBase.PropertyInfo == null\n                                || !navigationBase.PropertyInfo.GetMethod!.IsReallyVirtual())\n                            {\n                                if (!_options.IgnoreNonVirtualNavigations\n                                    && navigationBase is not INavigation { ForeignKey.IsOwnership: true })","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Proxies/Proxies/Internal/ProxyBindingRewriter.cs#L68-L104","documentation":"When UseChangeTrackingProxies is enabled, ProxyBindingRewriter examines each declared navigation and skip-navigation. For change-tracking proxies, if a navigation has no CLR PropertyInfo (navigationBase.PropertyInfo == null — meaning it is a field-only or shadow navigation), it throws FieldProperty. Change-tracking proxies override property getters/setters to intercept changes, which is impossible without a CLR property to override.","triggerScenarios":"Enabling UseChangeTrackingProxies() when at least one navigation property is mapped without a CLR property — e.g. using [BackingField] with only a field and no property, or configuring a shadow navigation in OnModelCreating. The throw occurs during model finalization.","commonSituations":"Domain models that use field-only collections (e.g. private readonly List<Post> _posts with [BackingField]) for encapsulation. Configuring navigations entirely in fluent API without corresponding CLR properties. Combining DDD-style entity patterns with change-tracking proxies.","solutions":["Add a public or protected virtual CLR property for every navigation that currently has only a field.","Switch to UseLazyLoadingProxies (which can tolerate field access via SetPropertyAccessMode) if full change-tracking proxies are not needed.","Do not enable UseChangeTrackingProxies if your model intentionally uses field-only navigations."],"exampleFix":"// before — field-only navigation, no CLR property\npublic class Blog\n{\n    [BackingField(\"_posts\")]\n    public ICollection<Post> Posts => _posts;\n    private readonly List<Post> _posts = new();\n}\n// UseChangeTrackingProxies() → throws FieldProperty\n\n// after — add a settable virtual CLR property\npublic class Blog\n{\n    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();\n}","handlingStrategy":"validation","validationCode":"// At startup, verify all navigations have CLR properties when change-tracking proxies are enabled.\nstatic void ValidateNavigationProperties(ModelBuilder modelBuilder)\n{\n    foreach (var entityType in modelBuilder.Model.GetEntityTypes())\n    {\n        foreach (var nav in entityType.GetDeclaredNavigations()\n                     .Concat<INavigationBase>(entityType.GetDeclaredSkipNavigations()))\n        {\n            if (!nav.IsShadowProperty() && nav.PropertyInfo == null)\n            {\n                throw new InvalidOperationException(\n                    $\"{entityType.DisplayName()}.{nav.Name} has no CLR property; \" +\n                    \"change-tracking proxies require one.\");\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    using var context = new MyContext(options);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"mapped without a CLR property\"))\n{\n    // Add a CLR property for the navigation, or switch to lazy-loading proxies\n    logger.LogError(ex, \"Navigation lacks CLR property; change-tracking proxies need one.\");\n    throw;\n}","preventionTips":["Ensure every navigation has a public or protected virtual CLR property (not field-only).","Avoid [BackingField]-only navigations when using change-tracking proxies.","Validate entity metadata at startup to catch field-only navigations early.","Consider lazy-loading proxies or explicit loading if field-only navigations are required."],"tags":["efcore","proxies","change-tracking","navigation","field-only","model-building"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}