diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 11a96d52c2e..c9fa6a37250 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -1162,8 +1162,12 @@ typy_richcompare (PyObject *self, PyObject *other, int op)
 
 
 
+/* Forward declaration, see below.  */
+static void
+set_type (type_object *obj, struct type *type);
+
 /* Deleter that saves types when an objfile is being destroyed.  */
-struct typy_deleter
+struct typy_deleter_for_objfile_owned
 {
   void operator() (type_object *obj)
   {
@@ -1181,35 +1185,74 @@ struct typy_deleter
 	type_object *next = obj->next;
 
 	copied_types.clear ();
-	obj->type = copy_type_recursive (obj->type, copied_types);
 
-	obj->next = NULL;
-	obj->prev = NULL;
+	/* Set a copied (now arch-owned) type.  As a side-effect this
+	   adds OBJ to per-arch list.  We do not need to remove it from
+	   per-objfile list since the objfile is going to go completely
+	   anyway.  */
+	set_type (obj, copy_type_recursive (obj->type, copied_types));
 
 	obj = next;
       }
   }
 };
 
-static const registry<objfile>::key<type_object, typy_deleter>
+/* Deleter that is used when an arch is is about to be freed.  */
+struct typy_deleter_for_arch_owned
+{
+  void operator() (type_object *obj)
+  {
+    while (obj)
+      {
+	type_object *next = obj->next;
+
+	obj->type = nullptr;
+
+	obj->next = nullptr;
+	obj->prev = nullptr;
+
+	obj = next;
+      }
+  }
+};
+
+
+
+static const registry<objfile>::key<type_object, typy_deleter_for_objfile_owned>
      typy_objfile_data_key;
+static const registry<gdbarch>::key<type_object, typy_deleter_for_arch_owned>
+     typy_gdbarch_data_key;
 
 static void
 set_type (type_object *obj, struct type *type)
 {
   obj->type = type;
-  obj->prev = NULL;
-  if (type != nullptr && type->objfile_owner () != nullptr)
+  obj->prev = nullptr;
+
+  /* Can it really happen that type is NULL?  */
+  if (type != nullptr)
     {
-      struct objfile *objfile = type->objfile_owner ();
+      if (type->objfile_owner () != nullptr)
+	{
+	  struct objfile *objfile = type->objfile_owner ();
+
+	  obj->next = typy_objfile_data_key.get (objfile);
+	  if (obj->next)
+	    obj->next->prev = obj;
+	  typy_objfile_data_key.set (objfile, obj);
+	}
+      else
+	{
+	  struct gdbarch *arch = type->arch_owner ();
 
-      obj->next = typy_objfile_data_key.get (objfile);
-      if (obj->next)
-	obj->next->prev = obj;
-      typy_objfile_data_key.set (objfile, obj);
+	  obj->next = typy_gdbarch_data_key.get (arch);
+	  if (obj->next)
+	    obj->next->prev = obj;
+	  typy_gdbarch_data_key.set (arch, obj);
+	}
     }
   else
-    obj->next = NULL;
+    obj->next = nullptr;
 }
 
 static void
@@ -1219,13 +1262,19 @@ typy_dealloc (PyObject *obj)
 
   if (type->prev)
     type->prev->next = type->next;
-  else if (type->type != nullptr && type->type->objfile_owner () != nullptr)
+  else if (type->type != nullptr)
     {
-      /* Must reset head of list.  */
-      struct objfile *objfile = type->type->objfile_owner ();
-
-      if (objfile)
-	typy_objfile_data_key.set (objfile, type->next);
+      if (type->type->is_objfile_owned ())
+	{
+	  /* Must reset head of list.  */
+	  struct objfile *objfile = type->type->objfile_owner ();
+	  typy_objfile_data_key.set (objfile, type->next);
+	}
+      else
+	{
+	  struct gdbarch *arch = type->type->arch_owner ();
+	  typy_gdbarch_data_key.set (arch, type->next);
+	}
     }
   if (type->next)
     type->next->prev = type->prev;
@@ -1473,6 +1522,23 @@ type_to_type_object (struct type *type)
       return gdbpy_handle_gdb_exception (nullptr, except);
     }
 
+  /* Look if there's already a gdb.Type object for given TYPE
+     and if so, return it.  */
+  if (type->is_objfile_owned ())
+    type_obj = typy_objfile_data_key.get (type->objfile_owner ());
+  else
+    type_obj = typy_gdbarch_data_key.get (type->arch_owner ());
+
+  while (type_obj != nullptr)
+    {
+      if (type_obj->type == type)
+	{
+	  Py_INCREF (type_obj);
+	  return (PyObject*)type_obj;
+	}
+      type_obj = type_obj->next;
+    }
+
   type_obj = PyObject_New (type_object, &type_object_type);
   if (type_obj)
     set_type (type_obj, type);
diff --git a/gdb/testsuite/gdb.python/py-arch.exp b/gdb/testsuite/gdb.python/py-arch.exp
index c76fc778117..c294011ac69 100644
--- a/gdb/testsuite/gdb.python/py-arch.exp
+++ b/gdb/testsuite/gdb.python/py-arch.exp
@@ -108,6 +108,11 @@ gdb_test "python print(arch.void_type())" \
     "void" \
     "get void type"
 
+# Test type identity
+gdb_test "python print(arch.integer_type(32) is arch.integer_type(32))" \
+    "True" \
+    "arch.integer_type(32) always return the same Python object"
+
 # Test for gdb.architecture_names().  First we're going to grab the
 # complete list of architecture names using the 'complete' command.
 set arch_names []
diff --git a/gdb/testsuite/gdb.python/py-type.exp b/gdb/testsuite/gdb.python/py-type.exp
index 7e469c93c35..c9d4353e488 100644
--- a/gdb/testsuite/gdb.python/py-type.exp
+++ b/gdb/testsuite/gdb.python/py-type.exp
@@ -324,6 +324,19 @@ proc test_type_equality {} {
     }
 }
 
+# Test type identity
+proc test_type_identity {} {
+    gdb_test_no_output "python v1 = gdb.parse_and_eval('global_unsigned_int')"
+    gdb_test_no_output "python v2 = gdb.parse_and_eval('global_unsigned_int')"
+
+    gdb_test "python print(v1.type is v2.type)" "True"
+
+    gdb_test_no_output "python t1 = gdb.lookup_type ('char')"
+    gdb_test_no_output "python t2 = gdb.lookup_type ('char')"
+
+    gdb_test "python print(t1 is t2)" "True"
+}
+
 # Test the gdb.Type.is_scalar property.
 proc test_is_scalar { lang } {
     if {$lang == "c++"} {
@@ -376,6 +389,7 @@ if { [build_inferior "${binfile}" "c"] == 0 } {
       test_is_scalar "c"
       test_is_signed "c"
       test_type_equality
+      test_type_identity
   }
 }
 
@@ -392,6 +406,7 @@ if { [build_inferior "${binfile}-cxx" "c++"] == 0 } {
       test_is_scalar "c++"
       test_is_signed "c++"
       test_type_equality
+      test_type_identity
   }
 }
 
