diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 12b69ed6ebe..50dbb47b82c 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -970,13 +970,15 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
 
       c_type_print_template_args (&local_flags, type, stream, language);
 
-      /* Add in template parameters when printing derivation info.  */
-      if (local_flags.local_typedefs != NULL)
+      if (local_flags.local_typedefs != nullptr
+	  && !HAS_TEMPLATE_TYPE_MEMBER (type))
 	local_flags.local_typedefs->add_template_parameters (type);
       cp_type_print_derivation_info (stream, type, &local_flags);
 
-      /* This holds just the global typedefs and the template
-	 parameters.  */
+      /* This holds just the global typedefs, and the template type
+	 parameters in case the condition HAS_TEMPLATE_TYPE_MEMBER
+	 (type) is not fulfilled.  */
+
       struct type_print_options semi_local_flags = *flags;
       semi_local_flags.local_typedefs = NULL;
 
diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index 252072b66dd..ffbf619e0ab 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -131,6 +131,12 @@ cp_print_value_fields (struct value *val, struct ui_file *stream,
   static int last_set_recurse = -1;
 
   struct type *type = check_typedef (val->type ());
+  
+  /* For templated types we want to print the value based on its target
+     type.  */
+  if (val->type ()->code () == TYPE_CODE_TEMPLATE_TYPE_PARAM
+      && val->type ()->target_type () != nullptr)
+    type = type->target_type ();
 
   if (recurse == 0)
     {
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 1525e8e4d39..297e01a343b 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -11489,8 +11489,31 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
       struct field_info fi;
       std::vector<struct symbol *> template_args;
 
+      if (cu->lang () == language_cplus)
+	{
+	  if (!HAVE_CPLUS_STRUCT (type))
+	    ALLOCATE_CPLUS_STRUCT_TYPE (type);
+	  HAS_TEMPLATE_TYPE_MEMBER (type) = false;
+	}
+
       for (die_info *child_die : die->children ())
-	handle_struct_member_die (child_die, type, &fi, &template_args, cu);
+	{
+	  handle_struct_member_die (child_die, type, &fi, &template_args, cu);
+
+	  /* This is a heuristic to detect when DWARF actually references
+	     template type parameter DIEs.  */
+	  if (!template_args.empty () && !HAS_TEMPLATE_TYPE_MEMBER (type))
+	    {
+	      attribute *type_attr = dwarf2_attr (child_die, DW_AT_type, cu);
+	      if (type_attr != nullptr && type_attr->form_is_ref ())
+		{
+		  die_info *type_die
+		    = follow_die_ref (child_die, type_attr, &cu);
+		  if (type_die->tag == DW_TAG_template_type_param)
+		    HAS_TEMPLATE_TYPE_MEMBER (type) = true;
+		}
+	    }
+	}
 
       /* Attach template arguments to type.  */
       if (!template_args.empty ())
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 3ae5a1ef484..c9a67210cff 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1783,6 +1783,12 @@ struct cplus_struct_type
        classes.  */
 
     struct symbol **template_arguments;
+
+    /* Flag used in the heuristic to detect a specific DWARF format for
+       type DIEs describing source entities referring to the formal template
+       type parameter.  This flag is true if such type DIEs refer to a
+       DW_TAG_template_type_parameter DIE, otherwise it is set to false.  */
+    bool has_template_type_member;
   };
 
 /* * Struct used to store conversion rankings.  */
@@ -1991,6 +1997,8 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
   TYPE_CPLUS_SPECIFIC (thistype)->n_template_arguments
 #define TYPE_TEMPLATE_ARGUMENTS(thistype) \
   TYPE_CPLUS_SPECIFIC (thistype)->template_arguments
+#define HAS_TEMPLATE_TYPE_MEMBER(thistype) \
+  TYPE_CPLUS_SPECIFIC (thistype)->has_template_type_member
 #define TYPE_TEMPLATE_ARGUMENT(thistype, n) \
   TYPE_CPLUS_SPECIFIC (thistype)->template_arguments[n]
 
diff --git a/gdb/testsuite/gdb.cp/template-type-parameters.cc b/gdb/testsuite/gdb.cp/template-type-parameters.cc
new file mode 100644
index 00000000000..9cb0a25062b
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/template-type-parameters.cc
@@ -0,0 +1,95 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright (C) 2025 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+template <typename T, typename U>
+struct A
+{
+  A () : t_val (), u_val (), i_val (), f_val () { }
+  T t_val;
+  U u_val;
+  int i_val;
+  float f_val;
+
+  T tfunc (T tval, U uval)
+  {
+    return tval;
+  }
+
+  int ifunc (int ival, T tval)
+  {
+    return ival;
+  }
+
+  float ffunc (float fval, U uval)
+  {
+    return fval;
+  }
+};
+
+template<typename T>
+struct B {
+  T t_val;
+
+  template<typename U>
+  struct C {
+    U u_val;
+  };
+
+  C<T> c;
+};
+
+int
+main ()
+{
+  A<int, int> a;
+  a.t_val = 1;
+  a.u_val = 2;
+  a.i_val = 3;
+  a.f_val = 4.0f;
+
+  A<float, float> b;
+  b.t_val = 1;
+  b.u_val = 2.0f;
+  b.i_val = 3;
+  b.f_val = 4.0f;
+
+  A<float, int> c;
+  c.t_val = 1.0;
+  c.u_val = 2;
+  c.i_val = 3;
+  c.f_val = 4.0f;
+
+  A<A<float, int>, A<float, float>> d;
+  d.t_val = c;
+  d.u_val = b;
+  d.i_val = 3;
+  d.f_val = 4.0f;
+
+  A<A<float, float>, A<float, float>> e;
+  e.t_val = b;
+  e.u_val = b;
+  e.i_val = 3;
+  e.f_val = 4.0f;
+
+  B<int> f;
+  f.t_val = 1;
+
+  B<B<int>> g;
+  g.t_val = f;
+
+  return 0; /* Break here.  */
+}
diff --git a/gdb/testsuite/gdb.cp/template-type-parameters.exp b/gdb/testsuite/gdb.cp/template-type-parameters.exp
new file mode 100644
index 00000000000..173a09f4b3c
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/template-type-parameters.exp
@@ -0,0 +1,195 @@
+# Copyright 2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Test extended template type resolution for a DWARF format which allows
+# GDB to differentiate between template types and normal types, which have
+# the same target type.
+#
+# This test is only supported in case a compiler is used which supports a
+# specific DWARF format for type references of DIEs that describe source
+# entities referring to the formal template parameter.
+# They must reference the DW_TAG_template_type_parameter DIE, and not the
+# underlying type DIE.
+#
+# This format is described in the DWARF 5 spec:
+# "A template type parameter is represented by a debugging information
+# entry with the tag DW_TAG_template_type_parameter."
+# which also lists the following example (Figure D.51):
+#    ! DWARF description
+#    !
+#    11$: DW_TAG_structure_type
+#	    DW_AT_name("wrapper")
+#
+#    12$: DW_TAG_template_type_parameter
+#	    DW_AT_name("T")
+#	    DW_AT_type(reference to "int")
+#
+#    13$: DW_TAG_member
+#	    DW_AT_name("comp")
+#	    DW_AT_type(reference to 12$)
+#
+#    14$: DW_TAG_variable
+#	    DW_AT_name("obj")
+#	    DW_AT_type(reference to 11$)
+#
+# For current versions of GCC and Clang this test will fail.
+
+standard_testfile .cc
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug} ] } {
+    return
+}
+
+if { ![runto_main] } {
+    return
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here."]
+gdb_continue_to_breakpoint "Break here."
+
+# Test same target type int.
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype a" \
+    [multi_line "type = struct A<int, int> \\\[with T = int, U = int\\\] {" \
+	".*T t_val;.*" \
+	".*U u_val;.*" \
+	".*int i_val;.*" \
+	".*float f_val;.*" \
+	".*A\\(void\\);.*" \
+	".*T tfunc\\(T, U\\);.*" \
+	".*int ifunc\\(int, T\\);.*" \
+	".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype a.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype a.u_val" "type = U"
+gdb_test "ptype a.i_val" "type = int"
+gdb_test "ptype a.f_val" "type = float"
+
+set val "{t_val = 1, u_val = 2, i_val = 3, f_val = 4}"
+gdb_test "print a" "$val"
+
+# Test same target type float.
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype b" \
+    [multi_line "type = struct A<float, float> \\\[with T = float, U = float\\\] {" \
+	".*T t_val;.*" \
+	".*U u_val;.*" \
+	".*int i_val;.*" \
+	".*float f_val;.*" \
+	".*A\\(void\\);.*" \
+	".*T tfunc\\(T, U\\);.*" \
+	".*int ifunc\\(int, T\\);.*" \
+	".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype b.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype b.u_val" "type = U"
+gdb_test "ptype b.i_val" "type = int"
+gdb_test "ptype b.f_val" "type = float"
+
+gdb_test "print b" "$val"
+
+# Test different target types.
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype c" \
+    [multi_line "type = struct A<float, int> \\\[with T = float, U = int\\\] {" \
+	".*T t_val;.*" \
+	".*U u_val;.*" \
+	".*int i_val;.*" \
+	".*float f_val;.*" \
+	".*A\\(void\\);.*" \
+	".*T tfunc\\(T, U\\);.*" \
+	".*int ifunc\\(int, T\\);.*" \
+	".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype c.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype c.u_val" "type = U"
+gdb_test "ptype c.i_val" "type = int"
+gdb_test "ptype c.f_val" "type = float"
+
+gdb_test "print c" "$val"
+
+# Test nested template types: d
+gdb_test "ptype d" \
+    [multi_line "type = struct A<A<float, int>, A<float, float> > \\\[with T = A<float, int>, U = A<float, float>\\\] {" \
+	".*T t_val;.*" \
+	".*U u_val;.*" \
+	".*int i_val;.*" \
+	".*float f_val;.*" \
+	".*A\\(void\\);.*" \
+	".*T tfunc\\(T, U\\);.*" \
+	".*int ifunc\\(int, T\\);.*" \
+	".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype d.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype d.u_val" "type = U"
+gdb_test "ptype d.i_val" "type = int"
+gdb_test "ptype d.f_val" "type = float"
+
+gdb_test "print d" "{t_val = $val, u_val = $val, i_val = 3, f_val = 4}"
+
+# Test nested template types: e
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype e" \
+    [multi_line "type = struct A<A<float, float>, A<float, float> > \\\[with T = A<float, float>, U = A<float, float>\\\] {" \
+	".*T t_val;.*" \
+	".*U u_val;.*" \
+	".*int i_val;.*" \
+	".*float f_val;.*" \
+	".*A\\(void\\);.*" \
+	".*T tfunc\\(T, U\\);.*" \
+	".*int ifunc\\(int, T\\);.*" \
+	".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype e.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype e.u_val" "type = U"
+gdb_test "ptype e.i_val" "type = int"
+gdb_test "ptype e.f_val" "type = float"
+
+gdb_test "print e" "{t_val = $val, u_val = $val, i_val = 3, f_val = 4}"
+
+gdb_test "ptype f" \
+    [multi_line "type = struct B<int> \\\[with T = int\\\] {" \
+	".*T t_val;.*" \
+	".*B<T>::C<T> c;.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype f.t_val" "type = T"
+
+gdb_test "ptype f.c" \
+    [multi_line "type = struct B<int>::C<int> \\\[with U = int\\\] {" \
+	".*U u_val;.*" ]
+
+gdb_test "ptype g" \
+    [multi_line "type = struct B<B<int> > \\\[with T = B<int>\\\] {" \
+	".*T t_val;.*" \
+	".*B<T>::C<T> c;.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype g.t_val" "type = T"
+
+gdb_test "ptype g.c" \
+    [multi_line "type = struct B<B<int> >::C<B<int> > \\\[with U = B<int>\\\] {" \
+	".*U u_val;.*" ]
+
diff --git a/gdb/testsuite/gdb.dwarf2/template-type-resolution.cc b/gdb/testsuite/gdb.dwarf2/template-type-resolution.cc
index 56d9f490fe2..881617f8a63 100644
--- a/gdb/testsuite/gdb.dwarf2/template-type-resolution.cc
+++ b/gdb/testsuite/gdb.dwarf2/template-type-resolution.cc
@@ -15,10 +15,13 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-template <typename T>
+template <typename T, typename U>
 struct A
 {
   T me_t;
+  int me_int;
+  U me_u;
+  float me_float;
 
   T t_func (T tval)
   {
@@ -27,7 +30,9 @@ struct A
 
 };
 
-A<int> var = {0};
+A<int, float> var = {0, 0, 0.0f, 0.0f};
+A<A<float, float>, A<float, float>> nestedvar
+  = {{0.0f, 0, 0.0f, 0.0f}, 0, {0.0f, 0, 0.0f, 0.0f}, 0.0f};
 
 int
 main ()
diff --git a/gdb/testsuite/gdb.dwarf2/template-type-resolution.exp b/gdb/testsuite/gdb.dwarf2/template-type-resolution.exp
index 4e9cc70d0fe..82788bdfda2 100644
--- a/gdb/testsuite/gdb.dwarf2/template-type-resolution.exp
+++ b/gdb/testsuite/gdb.dwarf2/template-type-resolution.exp
@@ -57,16 +57,21 @@ if { ![runto_main] } {
 }
 
 set int_size [get_sizeof "int" -1]
+set float_size [get_sizeof "float" -1]
 
 set asm_file1 [standard_output_file $srcfile2]
 Dwarf::assemble $asm_file1 {
-    global int_size
+    global int_size float_size
     cu {} {
 	DW_TAG_compile_unit {
 	    DW_AT_language @DW_LANG_C_plus_plus
 	} {
-	    declare_labels int
-	    declare_labels A template_type_int template_pointer1
+	    declare_labels int float
+	    declare_labels A template_type_float template_type_int
+	    declare_labels template_pointer1 template_pointer2 template_pointer3
+	    declare_labels nestedvar_type template_type_floatfloat
+	    declare_labels template_type_float2 template_type_float3
+	    declare_labels template_type_float4 template_type_float5
 
 	    int: DW_TAG_base_type {
 		DW_AT_name "int"
@@ -74,22 +79,44 @@ Dwarf::assemble $asm_file1 {
 		DW_AT_encoding @DW_ATE_signed
 	    }
 
+	    float: DW_TAG_base_type {
+		DW_AT_name "float"
+		DW_AT_byte_size 4 DW_FORM_sdata
+		DW_AT_encoding @DW_ATE_float
+	    }
+
 	    DW_TAG_subprogram {
 		MACRO_AT_func "main"
 	    }
 
 	    A: DW_TAG_structure_type {
 		DW_AT_name "A"
-		DW_AT_byte_size $int_size DW_FORM_sdata
+		DW_AT_byte_size 2*$int_size+2*$float_size DW_FORM_sdata
 	    } {
 		template_type_int: DW_TAG_template_type_param {
 		    DW_AT_type :$int
 		    DW_AT_name "T"
 		}
+		template_type_float: DW_TAG_template_type_param {
+		    DW_AT_type :$float
+		    DW_AT_name "U"
+		}
 		DW_TAG_member {
 		    DW_AT_name "me_t"
 		    DW_AT_type :$template_type_int
 		}
+		DW_TAG_member {
+		    DW_AT_name "me_int"
+		    DW_AT_type :$int
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_u"
+		    DW_AT_type :$template_type_float
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_float"
+		    DW_AT_type :$float
+		}
 
 		DW_TAG_subprogram {
 		    DW_AT_external 1 DW_FORM_flag
@@ -109,6 +136,7 @@ Dwarf::assemble $asm_file1 {
 	    }
 
 	    template_pointer1: DW_TAG_pointer_type {
+		DW_AT_byte_size 8 DW_FORM_data8
 		DW_AT_type :$A
 	    }
 
@@ -120,6 +148,117 @@ Dwarf::assemble $asm_file1 {
 		} SPECIAL_expr
 		DW_AT_external 1 DW_FORM_flag
 	    }
+
+	    template_type_floatfloat: DW_TAG_structure_type {
+		DW_AT_name "A"
+		DW_AT_byte_size 2*$int_size+2*$float_size DW_FORM_sdata
+	    } {
+		template_type_float2: DW_TAG_template_type_param {
+		    DW_AT_type :$float
+		    DW_AT_name "T"
+		}
+		template_type_float3: DW_TAG_template_type_param {
+		    DW_AT_type :$float
+		    DW_AT_name "U"
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_t"
+		    DW_AT_type :$template_type_float2
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_int"
+		    DW_AT_type :$int
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_u"
+		    DW_AT_type :$template_type_float3
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_float"
+		    DW_AT_type :$float
+		}
+
+		DW_TAG_subprogram {
+		    DW_AT_external 1 DW_FORM_flag
+		    DW_AT_name "t_func"
+		    DW_AT_type :$template_type_float2
+		    DW_AT_declaration 1 DW_FORM_flag
+		} {
+		      DW_TAG_formal_parameter {
+			  DW_AT_type :$template_pointer2
+			  DW_AT_artificial 1 DW_FORM_flag
+		      }
+
+		      DW_TAG_formal_parameter {
+			  DW_AT_type :$template_type_float2
+		      }
+		  }
+	    }
+
+	    template_pointer2: DW_TAG_pointer_type {
+		DW_AT_byte_size 8 DW_FORM_data8
+		DW_AT_type :$template_type_floatfloat
+	    }
+
+	    nestedvar_type: DW_TAG_structure_type {
+		DW_AT_name "A"
+		DW_AT_byte_size 2*$int_size+2*$float_size DW_FORM_sdata
+	    } {
+		template_type_float4: DW_TAG_template_type_param {
+		    DW_AT_type :$template_type_floatfloat
+		    DW_AT_name "T"
+		}
+		template_type_float5: DW_TAG_template_type_param {
+		    DW_AT_type :$template_type_floatfloat
+		    DW_AT_name "U"
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_t"
+		    DW_AT_type :$template_type_float4
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_int"
+		    DW_AT_type :$int
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_u"
+		    DW_AT_type :$template_type_float5
+		}
+		DW_TAG_member {
+		    DW_AT_name "me_float"
+		    DW_AT_type :$float
+		}
+
+		DW_TAG_subprogram {
+		    DW_AT_external 1 DW_FORM_flag
+		    DW_AT_name "t_func"
+		    DW_AT_type :$template_type_float4
+		    DW_AT_declaration 1 DW_FORM_flag
+		} {
+		      DW_TAG_formal_parameter {
+			  DW_AT_type :$template_pointer3
+			  DW_AT_artificial 1 DW_FORM_flag
+		      }
+
+		      DW_TAG_formal_parameter {
+			  DW_AT_type :$template_type_float4
+		      }
+		  }
+	    }
+
+	    template_pointer3: DW_TAG_pointer_type {
+		DW_AT_byte_size 8 DW_FORM_data8
+		DW_AT_type :$nestedvar_type
+	    }
+
+	     DW_TAG_variable {
+		DW_AT_name "nestedvar"
+		DW_AT_type :$nestedvar_type
+		DW_AT_location {
+		    DW_OP_addr [gdb_target_symbol "nestedvar"]
+		} SPECIAL_expr
+		DW_AT_external 1 DW_FORM_flag
+	    }
 	}
     }
 }
@@ -133,12 +272,196 @@ if { ![runto_main] } {
     return
 }
 
+# Setup strings used in the tests below.
+set var "{me_t = 0, me_int = 0, me_u = 0, me_float = 0}"
+set tfloatfloat "A<float, float>"
+
 gdb_test "ptype var" [multi_line \
-    "type = struct A<int> \\\[with T = int\\\] {" \
-    "    T me_t;.*" \
+"type = struct A<int, float> \\\[with T = int, U = float\\\] {" \
+    "    T me_t;" \
+    "    int me_int;" \
+    "    U me_u;" \
+    "    float me_float;.*" \
     "    T t_func\\\(T\\\);.*" \
-    "}"]
+"}"]
 
 gdb_test "ptype var.me_t" "type = T"
-gdb_test "print var" "\\\{me_t = 0\\\}"
+gdb_test "ptype var.me_int" "type = int"
+gdb_test "ptype var.me_u" "type = U"
+gdb_test "ptype var.me_float" "type = float"
+
+gdb_test "print var" "$var"
+
+gdb_test "ptype nestedvar" [multi_line \
+    "type = struct A<$tfloatfloat, $tfloatfloat > \\\[with T = $tfloatfloat, U = $tfloatfloat\\\] {" \
+    "    T me_t;" \
+    "    int me_int;" \
+    "    U me_u;" \
+    "    float me_float;.*" \
+    "    T t_func\\\(T\\\);.*" \
+"}"]
+gdb_test "ptype nestedvar.me_t" "type = T"
+gdb_test "ptype nestedvar.me_int" "type = int"
+gdb_test "ptype nestedvar.me_u" "type = U"
+gdb_test "ptype nestedvar.me_float" "type = float"
+
+gdb_test "print nestedvar" "{me_t = $var, me_int = 0, me_u = $var, me_float = 0}"
+
+# Tests for unnamed_var1-unnamed_var3 are basically the same as in
+# missing-type-name-for-template, but with the DWARF format described above.
+
+set asm_file_unnamed_templates [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file_unnamed_templates {
+    global int_size float_size
+    cu {} {
+	DW_TAG_compile_unit {
+	    DW_AT_language @DW_LANG_C_plus_plus
+	} {
+	    declare_labels int float
+	    declare_labels template_var1 template_type_float1 template_type_int1
+	    declare_labels template_var2 template_type_float2 template_type_int2
+	    declare_labels template_var3 template_type_float3 template_type_int3
+
+	    int: DW_TAG_base_type {
+		DW_AT_name "int"
+		DW_AT_byte_size 4 DW_FORM_data1
+		DW_AT_encoding @DW_ATE_signed
+	    }
+
+	    float: DW_TAG_base_type {
+		DW_AT_name "float"
+		DW_AT_byte_size 4 DW_FORM_sdata
+		DW_AT_encoding @DW_ATE_float
+	    }
+
+	    DW_TAG_subprogram {
+		MACRO_AT_func "main"
+	    }
+
+	    # A variable whose type is a template instantiation with two
+	    # template parameters, one unnamed.
+	    template_var1: DW_TAG_structure_type {
+		DW_AT_name "template_var1<int, float>"
+		DW_AT_byte_size $int_size+$float_size DW_FORM_sdata
+	    } {
+		template_type_int1: DW_TAG_template_type_param {
+		   DW_AT_type :$int
+		}
+		DW_TAG_member {
+		    DW_AT_name "me"
+		    DW_AT_type :$template_type_int1
+		}
+		template_type_float1: DW_TAG_template_type_param {
+		    DW_AT_name "second"
+		    DW_AT_type :$float
+		}
+		DW_TAG_member {
+		    DW_AT_name "me2"
+		    DW_AT_type :$template_type_float1
+		}
+	    }
+	    DW_TAG_variable {
+		DW_AT_name "unnamed_var1"
+		DW_AT_type :$template_var1
+	    }
+
+	    # A variable whose type is a template instantiation with two
+	    # template parameters, both unnamed.
+	    template_var2: DW_TAG_class_type {
+		DW_AT_name "template_var2<int, float>"
+		DW_AT_byte_size $int_size+$float_size DW_FORM_sdata
+	    } {
+		template_type_int2: DW_TAG_template_type_param {
+		   DW_AT_type :$int
+		}
+		DW_TAG_member {
+		    DW_AT_name "me"
+		    DW_AT_type :$template_type_int2
+		}
+		template_type_float2: DW_TAG_template_type_param {
+		    DW_AT_type :$float
+		}
+		DW_TAG_member {
+		    DW_AT_name "me2"
+		    DW_AT_type :$template_type_float2
+		}
+	    }
+	    DW_TAG_variable {
+		DW_AT_name "unnamed_var2"
+		DW_AT_type :$template_var2
+	    }
+
+	    # A variable whose type is a template instantiation with four
+	    # template arguments, two types, two values, all unnamed.
+	    template_var3: DW_TAG_structure_type {
+		DW_AT_name "template_var3"
+		DW_AT_byte_size $int_size+$float_size DW_FORM_sdata
+	    } {
+		DW_TAG_member {
+		    DW_AT_name "me"
+		    DW_AT_type :$template_type_int3
+		}
+		DW_TAG_template_value_param {
+		   DW_AT_type :$int
+		   DW_AT_const_value 0 DW_FORM_sdata
+		}
+		template_type_int3: DW_TAG_template_type_param {
+		    DW_AT_type :$int
+		}
+		DW_TAG_template_value_param {
+		    DW_AT_type :$int
+		    DW_AT_const_value 11 DW_FORM_sdata
+		}
+		template_type_float3: DW_TAG_template_type_param {
+		    DW_AT_type :$float
+		}
+		DW_TAG_member {
+		    DW_AT_name "me2"
+		    DW_AT_type :$template_type_float3
+		}
+	    }
+	    DW_TAG_variable {
+		DW_AT_name "unnamed_var3"
+		DW_AT_type :$template_var3
+	    }
+	}
+    }
+}
+
+set srcfile3 [file join $srcdir $subdir "missing-type-name-for-templates.cc"]
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+     [list $srcfile3 $asm_file_unnamed_templates] {debug c++}] } {
+    return
+}
+
+if { ![runto_main] } {
+    return
+}
+
+gdb_test "ptype unnamed_var1" [multi_line \
+    "type = struct template_var1<int, float> \\\[with <unnamed0> = int, second = float\\\] {" \
+    "    <unnamed0> me;" \
+    "    second me2;" \
+    "}"]
+
+gdb_test "ptype unnamed_var1.me" "type = <unnamed0>"
+gdb_test "ptype unnamed_var1.me2" "type = second"
+
+gdb_test "ptype unnamed_var2" [multi_line \
+    "type = class template_var2<int, float> \\\[with <unnamed0> = int, <unnamed1> = float\\\] {" \
+    "    <unnamed0> me;" \
+    "    <unnamed1> me2;" \
+    "}"]
+
+gdb_test "ptype unnamed_var2.me" "type = <unnamed0>"
+gdb_test "ptype unnamed_var2.me2" "type = <unnamed1>"
+
+gdb_test "ptype unnamed_var3" [multi_line \
+    "type = struct template_var3<0, int, 11, float> \\\[with <unnamed0> = 0, <unnamed1> = int, <unnamed2> = 11, <unnamed3> = float\\\] {" \
+    "    <unnamed1> me;" \
+    "    <unnamed3> me2;" \
+    "}"]
 
+gdb_test "ptype unnamed_var3.me" "type = <unnamed1>"
+gdb_test "ptype unnamed_var3.me2" "type = <unnamed3>"
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 4ba7a1aabfb..a30fe37edc8 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -224,12 +224,11 @@ typedef_hash_table::add_template_parameters (struct type *t)
       tf = XOBNEW (&m_storage, struct decl_field);
       tf->name = TYPE_TEMPLATE_ARGUMENT (t, i)->linkage_name ();
       type *arg_type = TYPE_TEMPLATE_ARGUMENT (t, i)->type ();
+
+      /* Skip self-referential template type parameters for the
+	 hashmap based substitution of template type parameters.  */
       if (arg_type == nullptr)
-	{
-	  /* Skip self-referential template type parameters for the
-	     hashmap based substitution of template type parameters.  */
-	  continue;
-	}
+	continue;
 
       tf->type = arg_type;
 
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 21931e7a589..d0d6397070f 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -119,7 +119,14 @@ extern const struct type_print_options type_print_raw_options;
 
 /* A hash table holding decl_field objects.  This is more complicated than an
    ordinary hash because it must also track the lifetime of some -- but not all
-   -- of the contained objects.  */
+   -- of the contained objects.
+   Once common compilers such as gcc and clang support DWARF format with DIE
+   type references describing source entities referring to the formal template
+   parameter that reference the DW_TAG_template_type_parameter, the usage of
+   this table for template type parameters is obsolete and can be removed.
+   However, as long as such DIE type references reference the underlying type
+   DIE this table can still be used, but will result in the issue desribed in
+   https://sourceware.org/bugzilla/show_bug.cgi?id=20540.  */
 
 class typedef_hash_table
 {
