https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70141
--- Comment #7 from Alexander Kondratskiy <kholdstare0.0 at gmail dot com> --- To add some color, maybe this is related to non-deduced contexts from 14.8.2.5p5 in the standard: The non-deduced contexts are: — The nested-name-specifier of a type that was specified using a qualified-id. So I agree that this should not work for code like the following, where the T in outer<T> is being deduced: template <typename T> struct outer { template <typename U> struct inner { }; }; // doesn't work, because non-deduced context template <typename T, typename U> void foo(typename outer<T>::template inner<U> val) { } void bar() { foo(typename outer<int>::template inner<double>{}); } But in the situation mentioned here, outer<T> is a concrete type, so anything within it should be deducible. If I get rid of the template parameter on outer, everything works fine, and the following code compiles: // no outer template! struct outer { template <typename U> struct inner { }; }; struct is_inner_for { template <typename Whatever> struct predicate { static constexpr bool value = false; }; template <typename U> struct predicate<outer::inner<U>> { static constexpr bool value = true; }; }; static_assert( is_inner_for::predicate< outer::inner<double> >::value, "Yay!" ); This simplified case where outer has no template parameter, in my mind should not be any different from the original problem - it's just that we had a template parameter but it was fully specified.