I just implemented a workaround that is certainly less than perfect, and does require a bit of code in your ViewModel (which. because the VM shouldn't know about the view, breaks strict MVVM).
Define your generic type, and then define a class of that type with the lowest-common-ancestor as the type argument:
class GenericClass<T> { }
class Class1 : GenericClass<Apples> { }
class Class2 : GenericClass<Oranges> { }
class WorkaroundClass : GenericClass<Fruit> { }
In your viewmodel you'll need to declare your bound member as the ancestor type, and cast it.
// instead of:
// Apple DisplayFruit => GetGrannySmith();
Fruit DisplayFruit => (Fruit)GetGrannySmith();
In your xaml, you can then bind your data template to the ancestor class:
<DataTemplate DataType="{x:Type WorkaroundClass}"/>
I'm pretty sure that because the Generic parent is, well, generic, you shouldn't run into any actual cases where the differences between your type arguments cause any problems.