diff --git a/Dependencies.targets b/Dependencies.targets
index 4db5d7707..45864c46e 100644
--- a/Dependencies.targets
+++ b/Dependencies.targets
@@ -13,7 +13,7 @@
-
+
@@ -46,6 +46,7 @@
+
diff --git a/src/EFCore.MySql.NTS/Storage/Internal/MySqlNetTopologySuiteTypeMappingSourcePlugin.cs b/src/EFCore.MySql.NTS/Storage/Internal/MySqlNetTopologySuiteTypeMappingSourcePlugin.cs
index c9bbd5d21..26a6da4d3 100644
--- a/src/EFCore.MySql.NTS/Storage/Internal/MySqlNetTopologySuiteTypeMappingSourcePlugin.cs
+++ b/src/EFCore.MySql.NTS/Storage/Internal/MySqlNetTopologySuiteTypeMappingSourcePlugin.cs
@@ -80,16 +80,28 @@ public virtual RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo ma
string defaultStoreType = null;
Type defaultClrType = null;
- return (clrType != null
- && TryGetDefaultStoreType(clrType, out defaultStoreType))
- || (storeTypeName != null
- && _spatialStoreTypeMappings.TryGetValue(storeTypeName, out defaultClrType))
- ? (RelationalTypeMapping)Activator.CreateInstance(
- typeof(MySqlGeometryTypeMapping<>).MakeGenericType(clrType ?? defaultClrType ?? typeof(Geometry)),
- _geometryServices,
- storeTypeName ?? defaultStoreType ?? "geometry",
- _options)
- : null;
+ var hasDefaultStoreType = clrType != null
+ && TryGetDefaultStoreType(clrType, out defaultStoreType);
+ var hasDefaultClrType = storeTypeName != null
+ && _spatialStoreTypeMappings.TryGetValue(storeTypeName, out defaultClrType);
+
+ // NOTE: If the incoming user-specified 'clrType' is of the known calculated 'defaultClrType', ONLY then proceeed
+ // with the creation of 'MySqlGeometryTypeMapping'.
+ var hasDefaultStoreOrClrType = hasDefaultStoreType || hasDefaultClrType;
+ var isClrTypeNotAssignable = clrType != null
+ && !clrType.IsAssignableFrom(defaultClrType);
+
+ if (!hasDefaultStoreOrClrType
+ || (!hasDefaultStoreType && isClrTypeNotAssignable))
+ {
+ return null;
+ }
+
+ return (RelationalTypeMapping)Activator.CreateInstance(
+ typeof(MySqlGeometryTypeMapping<>).MakeGenericType(clrType ?? defaultClrType ?? typeof(Geometry)),
+ _geometryServices,
+ storeTypeName ?? defaultStoreType ?? "geometry",
+ _options);
}
private static bool TryGetDefaultStoreType(Type type, out string defaultStoreType)
diff --git a/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj b/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj
index efe3e9273..3bbfea37f 100644
--- a/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj
+++ b/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj
@@ -32,6 +32,7 @@
+
diff --git a/test/EFCore.MySql.FunctionalTests/NTS/CustomValueConvertersForNonNTSClrTypesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/NTS/CustomValueConvertersForNonNTSClrTypesMySqlTest.cs
new file mode 100644
index 000000000..8ec72dfd2
--- /dev/null
+++ b/test/EFCore.MySql.FunctionalTests/NTS/CustomValueConvertersForNonNTSClrTypesMySqlTest.cs
@@ -0,0 +1,96 @@
+namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.NTS;
+
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using NetTopologySuite.Geometries;
+using Pomelo.EntityFrameworkCore.MySql.Tests;
+using Shouldly;
+using Xunit;
+
+public class CustomValueConvertersForNonNTSClrTypesMySqlTest
+{
+ [Fact]
+ public async Task NonNTS_ClrType_CanBe_Mapped_to_CustomValueConverters()
+ {
+ var services = new ServiceCollection()
+ .AddDbContext()
+ .AddSingleton(
+ new DbContextOptionsBuilder()
+ .UseMySql(
+ AppConfig.ConnectionString,
+ AppConfig.ServerVersion,
+ options =>
+ {
+ options.UseNetTopologySuite();
+ })
+ .EnableSensitiveDataLogging()
+ .LogTo(Console.WriteLine, LogLevel.Debug)
+ .Options);
+
+ var provider = services.BuildServiceProvider();
+ await using var context = provider.GetRequiredService();
+
+ // Validate `MySqlNetTopologySuiteTypeMappingSourcePlugin.FindMapping()` doesn't throw.
+ await Should.NotThrowAsync(context.Database.EnsureDeletedAsync());
+ await Should.NotThrowAsync(context.Database.EnsureCreatedAsync());
+ }
+}
+
+public sealed class CustomDbContext(DbContextOptions options) : DbContext(options)
+{
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ var testClass = modelBuilder.Entity();
+ testClass.Property(t => t.Vertices)
+ .HasColumnType("GEOMETRY")
+ .HasConversion(new MysqlGeometryWkbValueConverter());
+
+ var testClass2 = modelBuilder.Entity();
+ testClass2.Property(t => t.Vertices)
+ .HasColumnType("GEOMETRY");
+ }
+}
+
+public class TestClass
+{
+ public int Id { get; set; }
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
+ public byte[] Vertices { get; set; }
+#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
+}
+
+public class TestClass2
+{
+ public int Id { get; set; }
+
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
+ public Geometry Vertices { get; set; }
+#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
+}
+
+///
+/// MySql's internal geometry format is WKB with an initial 4
+/// bytes for the SRID:
+/// https://dev.mysql.com/doc/refman/5.7/en/gis-data-formats.html
+///
+public class MysqlGeometryWkbValueConverter : ValueConverter
+{
+ public MysqlGeometryWkbValueConverter()
+ : base(
+ clr => AddSRID(clr),
+ col => StripSRID(col))
+ {
+ }
+
+ private static byte[] AddSRID(byte[] wkb) =>
+ new byte[] { 0, 0, 0, 0, }.Concat(wkb).ToArray();
+
+ private static byte[] StripSRID(byte[] col) =>
+ col.Skip(4).ToArray();
+}