Java Generics: firma de método para (copia en profundidad de) mapas genéricos

tengo algunosMaps que ellos mismos pueden contener de nuevoMaps (de cualquier tipo). Escribí un método con la firma:

public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> s);

Sin embargo, ahora me gustaría generalizar este código para admitirMaps en general, pero sigue devolviendo un objeto del mismo tipo que el argumento. Así que en lugar de:

public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> s);
public static <K,V> CheckedMap<K,V> deepCopyCheckedMap(CheckedMap<K,V> s);
public static <K,V> TreeMap<K,V> deepCopyTreeMap(TreeMap<K,V> s);
...
etc.

Me gustaría algo como esto:

public static <K,V, M extends Map<K,V>> M<K,V> deepCopyMap(M<K,V> s);

Sin embargo, esto me da:

Multiple markers at this line
- The type M is not generic; it cannot be parameterized with arguments <K, 
 V>
- The type M is not generic; it cannot be parameterized with arguments <K, 
 V>

¿Cómo declaro correctamente la firma del método y sigo devolviendo un objeto del tipo correcto (sin usar la reflexión interna)?

Para este proyecto, agregar más dependencias no es realmente una opción, así que preferiría una solución que no dependa de bibliotecas externas. Además, he mirado en elCloneable interfaz, sin embargo, siendo solo una interfaz de marcador (sin implementación paraMaps en general) no me sirve de mucho.

Edición: como referencia, este es mi código para copias anidadasHashMaps (el código funciona correctamente):

public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> source){
    HashMap<K,V> result = new HashMap<K, V>();
    for(Map.Entry<K, V> entry : source.entrySet()){
        K k = entry.getKey();
        V v = entry.getValue();
        if(k instanceof HashMap<?,?>){
            k = (K) deepCopyHashMap((HashMap<?,?>) k);
        }
        if(v instanceof HashMap<?,?>){
            v = (V) deepCopyHashMap((HashMap<?,?>) v);
        }
        result.put(k, v);
    }
    return result;
}
Edición: Soluciones

Esta no es una solución ideal. Fallará si no hay un constructor predeterminado para el tipo de tiempo de ejecución de los anidados.Map. Lo he probado con anidadoHashMaps y el tipo de tiempo de ejecución se copia correctamente.

@SuppressWarnings("unchecked")
public static <K,V, M extends Map<K,V>> M deepCopyMap(M source) throws InstantiationException, IllegalAccessException{
    M result = (M) source.getClass().newInstance();
    for(Map.Entry<K, V> entry : source.entrySet()){
        K k = entry.getKey();
        V v = entry.getValue();
        if(k instanceof Map<?,?>){
            k = (K) deepCopyMap((Map<?,?>) k);
        }
        if(v instanceof Map<?,?>){
            v = (V) deepCopyMap((Map<?,?>) v);
        }
        result.put(k, v);
    }
    return result;
}

Esto es mucho más seguro, pero todos los tipos conocidos deben enumerarse explícitamente:

@SuppressWarnings("unchecked")
public static <K,V, M extends Map<K,V>> M deepCopyMap(M source){
    M result;
    if(source instanceof HashMap){
        result = (M) new HashMap<K,V>();
    } else {
        //fail
    }
    // etc. add more types here
    for(Map.Entry<K, V> entry : source.entrySet()){
        K k = entry.getKey();
        V v = entry.getValue();
        if(k instanceof Map<?,?>){
            k = (K) deepCopyMap((Map<?,?>) k);
        }
        if(v instanceof Map<?,?>){
            v = (V) deepCopyMap((Map<?,?>) v);
        }
        result.put(k, v);
    }
    return result;
}

Respuestas a la pregunta(2)

Su respuesta a la pregunta