code: public static ParameterizedType getSuperParameterizedType(Type type, Class<?> superClass) {
      if (type instanceof Class<?> || type instanceof ParameterizedType) {
        outer:
        while (type != null && type != Object.class) {
          Class<?> rawType;
          if (type instanceof Class<?>) {
            // type is a class
            rawType = (Class<?>) type;
          } else {
            // current is a parameterized type
            ParameterizedType parameterizedType = (ParameterizedType) type;
            rawType = getRawClass(parameterizedType);
            // check if found Collection
            if (rawType == superClass) {
              // return the actual collection parameter
              return parameterizedType;
            }
            if (superClass.isInterface()) {
              for (Type interfaceType : rawType.getGenericInterfaces()) {
                // interface type is class or parameterized type
                Class<?> interfaceClass =
                    interfaceType instanceof Class<?>
                        ? (Class<?>) interfaceType
                        : getRawClass((ParameterizedType) interfaceType);
                if (superClass.isAssignableFrom(interfaceClass)) {
                  type = interfaceType;
                  continue outer;
                }
              }
            }
          }
          // move on to the super class
          type = rawType.getGenericSuperclass();
        }
      }
      return null;
    }
docs: Returns the parameterized type that is or extends the given type that matches the given super
  class.
  
  <p>For example, if the input type is {@code HashMap<String,Integer>} and the input super class
  is {@code Map.class}, it will return the extended parameterized type {@link Map}, but which
  retains the actual type information from the original {@code HashMap}.
  
  @param type class or parameterized type
  @param superClass super class
  @return matching parameterized type or {@code null}