The JSON parser does not attempt to guess at the type of map elements. All JSON objects are parsed into maps of type Map<String,dynamic>. That allows you to add any value to the map and convert it back to JSON. The fact that your map only contains other maps as values might just be a happy coincidence, and make the type of the outer map Map<String, Map<String, dynamic>> would break code which expects to read data like this and then add other kinds of values to the outer map, like strings.
So, the type is Map<String, dynamic> If you know that it contains only maps, and you don't plan to change that, then you can do:
Map<String, dynamic> map = jsonDecode(...);
var mapmap = map.cast<String, Map<String, dynamic>>();
print(mapmap["key"]["otherKey"]);
This wraps the original map so that the values are cast to Map<String, dynamic> when you look them up, so you don't have to do it yourself.
If you then put something non-map into the original map, like map["gotcha"] = "string";, then mapmap["gotcha"] will throw a type error when you try to read it. So don't do that.
Map<string, dynamic>instead ofMap<String,Map<String,dynamic>>