Here is an algorithm to evaluate best matching System.Type for two types in hierarhy. This is one of answers for this StackOverflow question by Ken Kin:
Evaluate the maximum possible type to fit both of types
Algorithm
- Searching for common base class (either concrete or abstract)
FindBaseClassWithmethod
 - If there is no common base class, search for common implemented interface
- It's possible for one class to implement multiple interfaces, in this case return first common based interface
 FindInterfaceWithmethod
 
Questions
GetInterfaceHierarchyimplementaion- I'm not sure that this is correct implementation in case of complex class hierarhy with many implemented interfaces
 - Now all tests are passing for selected collection from BCL and my own testing hierarhy
 
- Are there any other flaws that I do not pay attention to?
 - I had wrote this sample in LinqPad, that's why all unittests are located at 
Mainmethod. Nevertheless, any improvments toTest.Assertare ok! 
Full source code with unittests is available here
// provide common base class or implemented interface
public static Type FindEqualTypeWith(this Type typeLeft, Type typeRight)
{
    if(typeLeft == null || typeRight == null) return null;
    var commonBaseClass = typeLeft.FindBaseClassWith(typeRight) ?? typeof(object);
    return commonBaseClass.Equals(typeof(object))
            ? typeLeft.FindInterfaceWith(typeRight)
            : commonBaseClass;
}
// searching for common base class (either concrete or abstract)
public static Type FindBaseClassWith(this Type typeLeft, Type typeRight)
{
    if(typeLeft == null || typeRight == null) return null;
    return typeLeft
            .GetClassHierarchy()
            .Intersect(typeRight.GetClassHierarchy())
            .FirstOrDefault(type => !type.IsInterface);
}
// searching for common implemented interface
// it's possible for one class to implement multiple interfaces, 
// in this case return first common based interface
public static Type FindInterfaceWith(this Type typeLeft, Type typeRight)
{
    if(typeLeft == null || typeRight == null) return null;
    return typeLeft
            .GetInterfaceHierarchy()
            .Intersect(typeRight.GetInterfaceHierarchy())
            .FirstOrDefault();   
}
// iterate on interface hierarhy
public static IEnumerable<Type> GetInterfaceHierarchy(this Type type)
{
    if(type.IsInterface) return new [] { type }.AsEnumerable();
    return type
            .GetInterfaces()
            .OrderByDescending(current => current.GetInterfaces().Count())
            .AsEnumerable();
}
// interate on class hierarhy
public static IEnumerable<Type> GetClassHierarchy(this Type type)
{
    if(type == null) yield break;
    Type typeInHierarchy = type;
    do
    {
        yield return typeInHierarchy;
        typeInHierarchy = typeInHierarchy.BaseType;
    }
    while(typeInHierarchy != null && !typeInHierarchy.IsInterface);
}