Как сделать класс для работы с JSON, который может содержать в себе объекты разных типов?
С ретрофитом вы наверняка используете какую-нибудь ConverterFactory для преобразования ответа в объект. Например, GsonConverterFactory (GSON). Рассмотрим ситуацию на его примере: 
Все объекты описываете как обычно,  кроме msg. Его описываете как интерфейс Message. Регистрируете: class MessageDeserializer implements JsonDeserializer<Message>{ ... }
...
Gson gson = new GsonBuilder()
                .registerTypeAdapter(Message.class, new MessageDeserializer())
                .create();
GsonConverterFactory.create(gson);
В методе public Message deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ... }
Десериализуете msg на основе тех данных, которые есть (надо научиться различать разные типы msg). Кладёте данные в разные реализации Message, например для {'txt':''} делаете такую реализацию:class MessageTxt implements Message {
    private final String txt;
    public MessageTxt(String txt){
        this.txt = txt;
    }
    String getTxt() { return txt; }
}
Сам интерфейс Message может вообще не содержать методов (маркерный интерфейс) или содержать общие для всех типов msg методы,  или дополнительно содержать метод для возвращения типа. Как-то так я бы поступил, видимо. Разные реализации Message потом можно просто проверять instaceof и кастовать.
А разве весь ответ в json формате не просто строка?
Ну и в зависимости от того как обрабатываете извлекаете уже данные нужного формата.
Не знаю, как в java, но в python это выглядит так: import sys
import json

response = json.loads(sys.stdin.read())
field1 = response['field1'] #'строка'
lst = response['list']['id'] # '123' - по сути это тоже строка, ибо числа в python без кавычек
если нужно получить число, то можно явно преобразовать в число 
lst = int(lst)
или так, если не знаешь число или не число:
try:
    lst = int(lst)
except ValueError:
    print "преобразовать не получилось"
Надо сказать, что строки, если они имеют вид чисел, скажем 123 или 1.23 преобразуются без проблем. 
А если json имеет встроенный json то можно дважды загрузить. сначала загружаешь и получаешь указатель на второй json, потом этот указатель загружаешь (loads) еще раз и получаешь и уже работаешь с ним также, как и раньше.