This is an expected behaviour. Gson has a list of default TypeAdapterFactory objects to use. You can see them in the source of the Gson class.
There are adapters for String, Number, Map, Collection... The last one is important and is used when no adapters can handle a type: it is the ReflectiveTypeAdapter. This one retrieves by reflection all the fields of the object to serialize, and searches for the appropriate adapters to serialize the values of the fields.
So when Gson has to serialize an object, first it tries to find an adapter by using the actual type of the object. If the adapter found is not the ReflectiveTypeAdapter, it uses it. Otherwise it searches an adapter with the declarative type and uses it if it's not the ReflectiveTypeAdapter. Otherwise it uses the ReflectiveTypeAdapter on the object (you can look at the source of the class TypeAdapterRuntimeTypeWrapper to have more details on this mecanism). That's the behaviour you have with your attribute MyInterface i.
When you do:
MyInterface i = new MyConcreteClass();
String json = gson.toJson(i);
Gson tries to find an adapter for the type MyConcreteClass and it finds the ReflectiveTypeAdapter. So now it should search for an adapter with the declarative type. But it has no way to know the declarative type because no object references it, this is the root object. You know in your code that you want to use the type MyInterface, but Gson has not this information and has only the object instance. You may think that Gson could see that the object implements MyInterface, but that's not the way it works (and what to do if the object implements two interfaces?)
So, you have two ways to solve your problem:
1) When you call Gson.toJson, you can give the declarative type for the root object: Gson#toJson(Object, Type)
String json = gson.toJson(i, MyInterface.class);
2) When you register your adapter, you can indicate that this adapter applies to all the subclasses: GsonBuilder#registerTypeHierarchyTree
GsonBuilder builder = new GsonBuilder()
.registerTypeHierarchyAdapter(MyInterface.class, new MySerializer());
Hope it helps