diff --git a/spring-cloud-function-context/pom.xml b/spring-cloud-function-context/pom.xml
index f6d6f25bf59f3c8f507578082a4bab2fcc1bf6cd..f1dd23ca316c21e940e317f54395bccd37bc33e7 100644
--- a/spring-cloud-function-context/pom.xml
+++ b/spring-cloud-function-context/pom.xml
@@ -16,6 +16,11 @@
 	</parent>
 
 	<dependencies>
+		<dependency>
+			<groupId>net.jodah</groupId>
+			<artifactId>typetools</artifactId>
+			<version>0.6.2</version>
+		</dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-autoconfigure</artifactId>
diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistry.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistry.java
index 386835a198116846c6b7af33935a77c37d2673b5..fc332e64a9a53fe42331c1040e62416466afde9c 100644
--- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistry.java
+++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistry.java
@@ -254,6 +254,9 @@ public class BeanFactoryAwareFunctionRegistry
 	}
 
 	private Type discoverFunctionType(Object function, String... names) {
+		if (function instanceof RoutingFunction) {
+			return FunctionType.of(FunctionContextUtils.findType(applicationContext.getBeanFactory(), names)).getType();
+		}
 		boolean beanDefinitionExists = false;
 		for (int i = 0; i < names.length && !beanDefinitionExists; i++) {
 			beanDefinitionExists = this.applicationContext.getBeanFactory().containsBeanDefinition(names[i]);
@@ -267,9 +270,15 @@ public class BeanFactoryAwareFunctionRegistry
 			logger.info("BeanDefinition for function name(s) '" + Arrays.asList(names) +
 				"' can not be located. FunctionType will be based on " + function.getClass());
 		}
-		return beanDefinitionExists
-			? FunctionType.of(FunctionContextUtils.findType(applicationContext.getBeanFactory(), names)).getType()
-			: new FunctionType(function.getClass()).getType();
+
+		Type type = FunctionTypeUtils.discoverFunctionTypeFromClass(function.getClass());
+		if (beanDefinitionExists) {
+			Type t = FunctionTypeUtils.getImmediateGenericType(type, 0);
+			if (t == null || t == Object.class) {
+				type = FunctionType.of(FunctionContextUtils.findType(this.applicationContext.getBeanFactory(), names)).getType();
+			}
+		}
+		return type;
 	}
 
 	private String discoverDefaultDefinitionIfNecessary(String definition) {
diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java
index 3390a0739a7fcb4e610466d6b4efdad64168088b..a87db468f7de2b7224ade5de2ef72ce9449a6594 100644
--- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java
+++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java
@@ -30,6 +30,7 @@ import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
+import net.jodah.typetools.TypeResolver;
 import org.reactivestreams.Publisher;
 import reactor.util.function.Tuple2;
 
@@ -118,29 +119,18 @@ public final class FunctionTypeUtils {
 		}
 	}
 
+	@SuppressWarnings("unchecked")
 	public static Type discoverFunctionTypeFromClass(Class<?> functionalClass) {
 		Assert.isTrue(isFunctional(functionalClass), "Type must be one of Supplier, Function or Consumer");
-		Type[] generics = functionalClass.getGenericInterfaces();
-		if (ObjectUtils.isEmpty(generics)) {
-			return functionalClass;
+
+		if (Function.class.isAssignableFrom(functionalClass)) {
+			return TypeResolver.reify(Function.class, (Class<Function<?, ?>>) functionalClass);
 		}
-		else  {
-			for (Type generic : generics) {
-				if (generic instanceof ParameterizedType) {
-					Class<?> rawClsss = (Class<?>) ((ParameterizedType) generic).getRawType();
-					if (Function.class.isAssignableFrom(rawClsss)
-							|| Consumer.class.isAssignableFrom(rawClsss)
-							|| Supplier.class.isAssignableFrom(rawClsss)) {
-						return generic;
-					}
-					else {
-						return discoverFunctionTypeFromClass(rawClsss);
-					}
-				}
-				else {
-					return discoverFunctionTypeFromClass((Class<?>) generic);
-				}
-			}
+		else if (Consumer.class.isAssignableFrom(functionalClass)) {
+			return TypeResolver.reify(Consumer.class, (Class<Consumer<?>>) functionalClass);
+		}
+		else if (Supplier.class.isAssignableFrom(functionalClass)) {
+			return TypeResolver.reify(Supplier.class, (Class<Supplier<?>>) functionalClass);
 		}
 		return null;
 	}
diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java
index 27ccad0a2e6d3caa31ef2e06e6ddf762627dfc6f..f170529c068f3759c32bd36b83cdb561ae3735e0 100644
--- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java
+++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java
@@ -41,6 +41,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.cloud.function.context.FunctionCatalog;
 import org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry.FunctionInvocationWrapper;
+import org.springframework.cloud.function.context.catalog.FunctionTypeUtilsTests.ReactiveFunction;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -356,7 +357,6 @@ public class BeanFactoryAwareFunctionRegistryTests {
 		assertThat(result.getPayload()).isEqualTo("\"b2xsZWg=\"".getBytes());
 	}
 
-	@SuppressWarnings("rawtypes")
 	@Test
 	public void testMultipleValuesInOutputHandling() throws Exception {
 		FunctionCatalog catalog = this.configureCatalog(CollectionOutConfiguration.class);
@@ -421,6 +421,29 @@ public class BeanFactoryAwareFunctionRegistryTests {
 		assertThat(dateResult.getHeaders().get("accept")).isNull();
 	}
 
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	@Test
+	public void testWithComplexHierarchyAndTypeConversion() {
+		FunctionCatalog catalog = this.configureCatalog(ReactiveFunctionImpl.class);
+		Function<Object, Flux> f = catalog.lookup("");
+		assertThat(f.apply(new GenericMessage("23")).blockFirst()).isEqualTo(23);
+		assertThat(f.apply(Flux.just("25")).blockFirst()).isEqualTo(25);
+		assertThat(f.apply(Flux.just(25)).blockFirst()).isEqualTo(25);
+	}
+
+	public interface ReactiveFunction<S, T> extends Function<Flux<S>, Flux<T>> {
+
+	}
+
+	@Component
+	@EnableAutoConfiguration
+	public static class ReactiveFunctionImpl implements ReactiveFunction<String, Integer> {
+		@Override
+		public Flux<Integer> apply(Flux<String> inFlux) {
+			return inFlux.map(v -> Integer.parseInt(v));
+		}
+	}
+
 	@SuppressWarnings("unchecked")
 	@EnableAutoConfiguration
 	public static class CollectionOutConfiguration {
diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java
index 3066418f758d57840cdcff80386818bd6e856620..a7b91fffb4b54f7ab1e3127030522948baf16dbd 100644
--- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java
+++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java
@@ -132,33 +132,12 @@ public class FunctionTypeUtilsTests {
 	}
 
 	@Test
-	public void foo() {
+	public void testWithComplexHierarchy() {
 		FunctionType type = FunctionType.of(FunctionTypeUtils.discoverFunctionTypeFromClass(ReactiveFunctionImpl.class));
 		assertThat(String.class).isAssignableFrom(type.getInputType());
 		assertThat(Integer.class).isAssignableFrom(type.getOutputType());
 	}
 
-//	@Test
-//	public void testInputTypeByIndex() throws Exception {
-//		Type functionType = getReturnType("function");
-//		Type inputType = FunctionTypeUtils.getInputType(functionType, 0);
-//		assertThat(inputType.getTypeName()).isEqualTo(String.class.getName());
-//		inputType = FunctionTypeUtils.getInputType(functionType, 1);
-//		assertThat(inputType.getTypeName()).isEqualTo(Integer.class.getName());
-//
-//		functionType = getReturnType("multiInputOutputPublisherFunction");
-//		inputType = FunctionTypeUtils.getInputType(functionType, 0);
-//		System.out.println("Reactive: " + FunctionTypeUtils.isReactive(inputType));
-//		System.out.println("Reactive: " + FunctionTypeUtils.getPublisherType(inputType));
-//		System.out.println("Reactive: " + FunctionTypeUtils.getImmediateGenericType(inputType, 0));
-//		System.out.println(inputType);
-//
-//		functionType = getReturnType("typelessFunction");
-//		inputType = FunctionTypeUtils.getInputType(functionType, 0);
-//		System.out.println(inputType);
-//	}
-
-
 	private static Function<String, Integer> function() {
 		return null;
 	}
@@ -246,6 +225,5 @@ public class FunctionTypeUtilsTests {
 		public Flux<Integer> apply(Flux<String> inFlux) {
 			return inFlux.map(v -> Integer.parseInt(v));
 		}
-
 	}
 }