Просто чтобы добавить это, я часто нахожу, что, имея дело со сложными словарями, которые вы описываете, гораздо лучше использовать с ними настоящие имена, чем пытаться позволить читателю кода разобраться.
Вы можете сделать это одним из двух способов в зависимости от личных предпочтений. Либо с помощью оператора using для создания псевдонима complier. Обратите внимание, что вы должны использовать полное имя типа, так как это псевдоним компилятора.
using ComplexKey = System.Collections.Generic.Dictionary<String, String>;
using ComplexType = System.Collections.Generic.Dictionary<
System.Collections.Generic.Dictionary<String, String>,
String
>;
Или вы можете пойти полным путем и создать класс, унаследованный от Dictionary.
class ComplexKey : Dictionary<String, String> { ... }
class ComplexType : Dictionary<ComplexKey, String> { ... }
Делая это, вам и читателю вашего кода будет намного легче понять, что вы делаете. Моё общее эмпирическое правило: если я создаю общий тип, то самое время взглянуть на создание первоклассных граждан, которые скорее представляют мою логику.