diff --git a/src/EFCore/Metadata/Internal/ForeignKey.cs b/src/EFCore/Metadata/Internal/ForeignKey.cs
index d0f5ad88e54..c328ec450c0 100644
--- a/src/EFCore/Metadata/Internal/ForeignKey.cs
+++ b/src/EFCore/Metadata/Internal/ForeignKey.cs
@@ -1210,6 +1210,13 @@ public static bool AreCompatible(
if (!ArePropertyTypesCompatible(principalProperties, dependentProperties))
{
+ if (principalEntityType.Model is Model model
+ && ReferenceEquals(model, dependentEntityType.Model)
+ && model.IsInModelSnapshot)
+ {
+ return true;
+ }
+
if (shouldThrow)
{
throw new InvalidOperationException(
diff --git a/src/EFCore/Metadata/Internal/Model.cs b/src/EFCore/Metadata/Internal/Model.cs
index dab7ec6d556..a1de99b8fcb 100644
--- a/src/EFCore/Metadata/Internal/Model.cs
+++ b/src/EFCore/Metadata/Internal/Model.cs
@@ -102,6 +102,20 @@ public virtual ModelDependencies? ScopedModelDependencies
set => _scopedModelDependencies = value;
}
+ ///
+ /// Gets a value indicating whether this model originated from a migration snapshot.
+ ///
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual bool IsInModelSnapshot
+ => ScopedModelDependencies == null
+ && _modelFinalizedConventions is { Count: 0 }
+ && FindAnnotation(CoreAnnotationNames.ProductVersion) != null;
+
///
/// Indicates whether the model is read-only.
///
diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs
index ccc47ab78c3..01a721bde3b 100644
--- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs
+++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs
@@ -121,6 +121,54 @@ protected override void BuildModel(ModelBuilder modelBuilder)
Assert.Equal(2, snapshot.Model.GetEntityTypes().Count());
}
+ [Fact]
+ public void Snapshot_with_mismatched_key_and_foreign_key_property_types_is_usable()
+ {
+ const string snapshotCode =
+ """
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+
+#nullable disable
+
+namespace RootNamespace;
+
+partial class Snapshot : ModelSnapshot
+{
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.0");
+
+ modelBuilder.Entity("Dependent", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasOne("Principal")
+ .WithMany()
+ .HasForeignKey("Id");
+ });
+
+ modelBuilder.Entity("Principal", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("smallint");
+
+ b.HasKey("Id");
+ });
+ }
+}
+
+""";
+
+ var snapshotModel = BuildModelFromSnapshotSource(snapshotCode);
+
+ Assert.Single(snapshotModel.FindEntityType("Dependent")!.GetForeignKeys());
+ }
+
[Fact]
public void Snapshot_with_migration_id()
{
diff --git a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs
index 275a48afaea..eb8bf76b96c 100644
--- a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs
+++ b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs
@@ -592,6 +592,18 @@ public virtual void Warns_on_double_uniquified_shadow_key_due_to_wrong_type()
modelBuilder);
}
+ [Fact]
+ public virtual void Passes_on_foreign_key_with_matching_model_type_and_mismatched_provider_type()
+ {
+ var modelBuilder = CreateConventionModelBuilder();
+
+ modelBuilder.Entity().HasOne().WithMany().HasForeignKey(a => a.P0).HasPrincipalKey(b => b.Id);
+ modelBuilder.Entity().Property(a => a.P0).HasConversion();
+ modelBuilder.Entity().Property(b => b.Id).HasConversion();
+
+ Validate(modelBuilder);
+ }
+
[Fact]
public virtual void Detects_shadow_key_referenced_by_foreign_key_by_convention()
{