diff --git a/src/Mapster.Tests/WhenImplicitInheritanceMapWithDerivedDestination.cs b/src/Mapster.Tests/WhenImplicitInheritanceMapWithDerivedDestination.cs
new file mode 100644
index 00000000..0bb500c9
--- /dev/null
+++ b/src/Mapster.Tests/WhenImplicitInheritanceMapWithDerivedDestination.cs
@@ -0,0 +1,75 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Shouldly;
+
+namespace Mapster.Tests
+{
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/947
+ ///
+ [TestClass]
+ public class WhenImplicitInheritanceMapWithDerivedDestination
+ {
+ [TestCleanup]
+ public void Cleanup()
+ {
+ TypeAdapterConfig.GlobalSettings.Clear();
+ TypeAdapterConfig.GlobalSettings.AllowImplicitDestinationInheritance = false;
+ }
+
+ [TestMethod]
+ public void Inherited_MapWith_On_Base_Destination_Casts_To_Derived_Destination()
+ {
+ var config = new TypeAdapterConfig();
+ config.AllowImplicitDestinationInheritance = true;
+ config.NewConfig()
+ .MapWith(src => src.Type == "Bird"
+ ? (Animal947)new Bird947 { AnimalValue = src.AnimalValueDto }
+ : new Dog947 { AnimalValue = src.AnimalValueDto });
+
+ var source = new AnimalDto947 { AnimalValueDto = "Hello", Type = "Dog" };
+
+ var dog = source.Adapt(config);
+
+ dog.ShouldBeOfType();
+ dog.AnimalValue.ShouldBe("Hello");
+ }
+
+ [TestMethod]
+ public void Inherited_MapWith_Works_For_Explicit_Source_Destination_Pair()
+ {
+ var config = new TypeAdapterConfig();
+ config.AllowImplicitDestinationInheritance = true;
+ config.NewConfig()
+ .MapWith(src => src.Type == "Bird"
+ ? (Animal947)new Bird947 { AnimalValue = src.AnimalValueDto }
+ : new Dog947 { AnimalValue = src.AnimalValueDto });
+
+ var source = new AnimalDto947 { AnimalValueDto = "Hello", Type = "Dog" };
+
+ var dog = source.Adapt(config);
+
+ dog.ShouldBeOfType();
+ dog.AnimalValue.ShouldBe("Hello");
+ }
+
+ public abstract class Animal947
+ {
+ public string AnimalValue { get; set; } = null!;
+ }
+
+ public class Dog947 : Animal947
+ {
+ }
+
+ public class Bird947 : Animal947
+ {
+ }
+
+ public class AnimalDto947
+ {
+ public string AnimalValueDto { get; set; } = null!;
+
+ public string Type { get; set; } = null!;
+ }
+ }
+}
diff --git a/src/Mapster/TypeAdapterConfig.cs b/src/Mapster/TypeAdapterConfig.cs
index 1dce2053..af88d5bd 100644
--- a/src/Mapster/TypeAdapterConfig.cs
+++ b/src/Mapster/TypeAdapterConfig.cs
@@ -431,7 +431,7 @@ private static LambdaExpression CreateMapExpression(CompileArgument arg)
throw new CompileException(arg, new InvalidOperationException("ConverterFactory is not found"));
try
{
- return fn(arg);
+ return AdjustInheritedConverterReturnType(fn(arg), arg);
}
catch (Exception ex)
{
@@ -439,6 +439,22 @@ private static LambdaExpression CreateMapExpression(CompileArgument arg)
}
}
+ private static LambdaExpression AdjustInheritedConverterReturnType(LambdaExpression lambda, CompileArgument arg)
+ {
+ var destinationType = arg.DestinationType;
+ var returnType = lambda.ReturnType;
+ if (returnType == destinationType)
+ return lambda;
+
+ // MapWith configured on a base destination type returns the base type, but implicit
+ // destination inheritance can compile the converter for a derived destination.
+ if (!returnType.IsAssignableFrom(destinationType))
+ return lambda;
+
+ var body = lambda.Body.To(destinationType, force: true);
+ return Expression.Lambda(body, lambda.Parameters);
+ }
+
private LambdaExpression CreateDynamicMapExpression(TypeTuple tuple)
{
var lambda = CreateMapExpression(tuple, MapType.Map);