         }
     }
 
+    fileprivate func unbox<T>(_ value: Any, as type: _JSONStringDictionaryDecodableMarker.Type) throws -> T? {
+        guard !(value is NSNull) else { return nil }
+
+        var result = [String : Any]()
+        guard let dict = value as? NSDictionary else {
+            throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
+        }
+        let elementType = type.elementType
+        for (key, value) in dict {
+            let key = key as! String
+            self.codingPath.append(_JSONKey(stringValue: key, intValue: nil))
+            defer { self.codingPath.removeLast() }
+
+            result[key] = try unbox_(value, as: elementType)
+        }
+
+        return result as? T
+    }
+
     fileprivate func unbox<T : Decodable>(_ value: Any, as type: T.Type) throws -> T? {
-        let decoded: T
+        return try unbox_(value, as: type) as? T
+    }
+
+    fileprivate func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? {
         #if DEPLOYMENT_RUNTIME_SWIFT
         // Bridging differences require us to split implementations here
-        if T.self == Date.self {
+        if type == Date.self {
             guard let date = try self.unbox(value, as: Date.self) else { return nil }
-            decoded = date as! T
-        } else if T.self == Data.self {
+            return date
+        } else if type == Data.self {
             guard let data = try self.unbox(value, as: Data.self) else { return nil }
-            decoded = data as! T
-        } else if T.self == URL.self {
+            return data
+        } else if type == URL.self {
             guard let urlString = try self.unbox(value, as: String.self) else {
                 return nil
             }

                                                                        debugDescription: "Invalid URL string."))
            }
            
            return (url as! T)
        } else if type == Decimal.self || type == NSDecimalNumber.self {
            return try self.unbox(value, as: Decimal.self) as? T
        } else {
            self.storage.push(container: value)
            defer { self.storage.popContainer() }
            return try type.init(from: self)
        }
        #endif
        
        return decoded
    }
}


//===----------------------------------------------------------------------===//

import CoreFoundation

/// A marker protocol used to determine whether a value is a `String`-keyed `Dictionary`
/// containing `Encodable` values (in which case it should be exempt from key conversion strategies).
///
fileprivate protocol _JSONStringDictionaryEncodableMarker { }

extension Dictionary : _JSONStringDictionaryEncodableMarker where Key == String, Value: Encodable { }

/// A marker protocol used to determine whether a value is a `String`-keyed `Dictionary`
/// containing `Decodable` values (in which case it should be exempt from key conversion strategies).
///
/// The marker protocol also provides access to the type of the `Decodable` values,
/// which is needed for the implementation of the key conversion strategy exemption.
///
fileprivate protocol _JSONStringDictionaryDecodableMarker {
    static var elementType: Decodable.Type { get }
}

extension Dictionary : _JSONStringDictionaryDecodableMarker where Key == String, Value: Decodable {
    static var elementType: Decodable.Type { return Value.self }
}

//===----------------------------------------------------------------------===//
// JSON Encoder
