public static Type wrapTypeAndReplaceTypeVariables(final Type type, final TypeMap typeMap) {
        if (isParameterizedType(type)) {
            final ParameterizedType parameterizedType = getAsParameterizedType(type);
            final Type[] wrappedArguments = wrapTypeParameters(parameterizedType.getActualTypeArguments(), typeMap);
            final Class<?> asClass = getAsClass(type);

            return new WrappedParameterizedType(asClass, wrappedArguments);
        }

        else if (isWildcard(type)) {
            final WildcardType wildcardType = (WildcardType) type;
            final Type[] wrappedUpperBounds = wrapTypeParameters(wildcardType.getUpperBounds(), typeMap);
            final Type[] wrappedLowerBounds = wrapTypeParameters(wildcardType.getLowerBounds(), typeMap);

            return new WrappedWildcardType(wrappedUpperBounds, wrappedLowerBounds);
        }

        else if (isGenericArrayType(type)) {
            final GenericArrayType genericArrayType = (GenericArrayType) type;
            final Type wrappedType = wrapTypeAndReplaceTypeVariables(genericArrayType.getGenericComponentType(), typeMap);

            return new WrappedGenericArrayType(wrappedType);
        }

        else if (isTypeVariable(type)) {
            final Type actualType = typeMap.getActualType((TypeVariable<?>) type);

            if (actualType != null) {
                return actualType;
            }
        }

        return type;
    }