Backport of _abccoll.py by Benjamin Arangueren, issue 1383.
With some changes of my own thrown in (e.g. backport of r58107).
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 978071b..bfb891c 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2127,13 +2127,6 @@
 	return dict_update_common(self, args, kwds, "dict");
 }
 
-static long
-dict_nohash(PyObject *self)
-{
-	PyErr_SetString(PyExc_TypeError, "dict objects are unhashable");
-	return -1;
-}
-
 static PyObject *
 dict_iter(PyDictObject *dict)
 {
@@ -2165,7 +2158,7 @@
 	0,					/* tp_as_number */
 	&dict_as_sequence,			/* tp_as_sequence */
 	&dict_as_mapping,			/* tp_as_mapping */
-	dict_nohash,				/* tp_hash */
+	0,					/* tp_hash */
 	0,					/* tp_call */
 	0,					/* tp_str */
 	PyObject_GenericGetAttr,		/* tp_getattro */
diff --git a/Objects/listobject.c b/Objects/listobject.c
index fb5ce82..deb3ca5 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -2393,13 +2393,6 @@
 	return 0;
 }
 
-static long
-list_nohash(PyObject *self)
-{
-	PyErr_SetString(PyExc_TypeError, "list objects are unhashable");
-	return -1;
-}
-
 static PyObject *list_iter(PyObject *seq);
 static PyObject *list_reversed(PyListObject* seq, PyObject* unused);
 
@@ -2694,7 +2687,7 @@
 	0,					/* tp_as_number */
 	&list_as_sequence,			/* tp_as_sequence */
 	&list_as_mapping,			/* tp_as_mapping */
-	list_nohash,				/* tp_hash */
+	0,					/* tp_hash */
 	0,					/* tp_call */
 	0,					/* tp_str */
 	PyObject_GenericGetAttr,		/* tp_getattro */
@@ -2959,4 +2952,3 @@
 		return 0;
 	return len;
 }
-
diff --git a/Objects/object.c b/Objects/object.c
index e75a03d..de385ea 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1902,7 +1902,7 @@
 	0,		/*tp_as_number*/
 	0,		/*tp_as_sequence*/
 	0,		/*tp_as_mapping*/
-	0,		/*tp_hash */
+	(hashfunc)_Py_HashPointer, /*tp_hash */
 };
 
 PyObject _Py_NoneStruct = {
diff --git a/Objects/setobject.c b/Objects/setobject.c
index 3cbcd9e..b049d09 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -789,13 +789,6 @@
 	return hash;
 }
 
-static long
-set_nohash(PyObject *self)
-{
-	PyErr_SetString(PyExc_TypeError, "set objects are unhashable");
-	return -1;
-}
-
 /***** Set iterator type ***********************************************/
 
 typedef struct {
@@ -2012,7 +2005,7 @@
 	&set_as_number,			/* tp_as_number */
 	&set_as_sequence,		/* tp_as_sequence */
 	0,				/* tp_as_mapping */
-	set_nohash,			/* tp_hash */
+	0,				/* tp_hash */
 	0,				/* tp_call */
 	0,				/* tp_str */
 	PyObject_GenericGetAttr,	/* tp_getattro */
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 59dec4a..1a221c8 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2590,12 +2590,6 @@
 	return f(self);
 }
 
-static long
-object_hash(PyObject *self)
-{
-	return _Py_HashPointer(self);
-}
-
 static PyObject *
 object_get_class(PyObject *self, void *closure)
 {
@@ -3030,7 +3024,7 @@
 	0,					/* tp_as_number */
 	0,					/* tp_as_sequence */
 	0,					/* tp_as_mapping */
-	object_hash,				/* tp_hash */
+	(hashfunc)_Py_HashPointer,		/* tp_hash */
 	0,					/* tp_call */
 	object_str,				/* tp_str */
 	PyObject_GenericGetAttr,		/* tp_getattro */
@@ -3236,6 +3230,33 @@
 		type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
 }
 
+/* Map rich comparison operators to their __xx__ namesakes */
+static char *name_op[] = {
+    "__lt__",
+    "__le__",
+    "__eq__",
+    "__ne__",
+    "__gt__",
+    "__ge__",
+    "__cmp__",
+ 	/* These are only for overrides_hash(): */
+    "__hash__",
+};
+
+static int
+overrides_hash(PyTypeObject *type)
+{
+	int i;
+	PyObject *dict = type->tp_dict;
+
+	assert(dict != NULL);
+	for (i = 0; i < 8; i++) {
+		if (PyDict_GetItemString(dict, name_op[i]) != NULL)
+			return 1;
+	}
+	return 0;
+}
+
 static void
 inherit_slots(PyTypeObject *type, PyTypeObject *base)
 {
@@ -3367,7 +3388,8 @@
 	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
 		if (type->tp_compare == NULL &&
 		    type->tp_richcompare == NULL &&
-		    type->tp_hash == NULL)
+		    type->tp_hash == NULL &&
+		    !overrides_hash(type))
 		{
 			type->tp_compare = base->tp_compare;
 			type->tp_richcompare = base->tp_richcompare;
@@ -3548,6 +3570,18 @@
 		}
 	}
 
+	/* Hack for tp_hash and __hash__.
+	   If after all that, tp_hash is still NULL, and __hash__ is not in
+	   tp_dict, set tp_dict['__hash__'] equal to None.
+	   This signals that __hash__ is not inherited.
+	*/
+	if (type->tp_hash == NULL &&
+	    PyDict_GetItemString(type->tp_dict, "__hash__") == NULL &&
+	    PyDict_SetItemString(type->tp_dict, "__hash__", Py_None) < 0)
+	{
+		goto error;
+	}
+
 	/* Some more special stuff */
 	base = type->tp_base;
 	if (base != NULL) {
@@ -4937,16 +4971,6 @@
 	return 0;
 }
 
-/* Map rich comparison operators to their __xx__ namesakes */
-static char *name_op[] = {
-	"__lt__",
-	"__le__",
-	"__eq__",
-	"__ne__",
-	"__gt__",
-	"__ge__",
-};
-
 static PyObject *
 half_richcompare(PyObject *self, PyObject *other, int op)
 {