code: @SuppressWarnings("unchecked")
      static Class<?> getParameterType(Object object, Class<?> expectedType) {
          Collection<Class<?>> extendedAndImplementedTypes =
                  getExtendedAndImplementedTypes(object.getClass(), new LinkedList<Class<?>>());
  
          for  (Class<?> type : extendedAndImplementedTypes) {
              Type[] implementedInterfaces  = type.getGenericInterfaces();
              for (Type implementedInterface : implementedInterfaces) {
                  if (implementedInterface instanceof ParameterizedType) {
                      ParameterizedType parameterizedCandidateType = (ParameterizedType) implementedInterface;
                      if (parameterizedCandidateType.getRawType().equals(expectedType)) {
                          Type[] typeArguments = parameterizedCandidateType.getActualTypeArguments();
                          Type typeArgument;
                          if (typeArguments.length == 0) {
                              typeArgument = Object.class;
                          } else {
                              typeArgument = parameterizedCandidateType.getActualTypeArguments()[0];
                          }
                          return (Class<?>) typeArgument;
                      }
                  }
              }
          }
          // This may never happen in case the caller checked if object instanceof expectedType
          throw new RuntimeException("Expected type " + expectedType +
                  " is not in class hierarchy of " + object.getClass());
      }
docs: Gets the type parameter of the expected generic interface which is
  actually used by the class of the given object. The generic
  interface can be implemented by an class or interface in the object's
  class hierarchy,
  
  @param object The object
  @param expectedType The expected generic interface
  @return The actually used parameter of the expected generic interface