diff --git a/src/multiset.c b/src/multiset.c
index 360cf94bb844f4abd6337e17628cf6a500a93481..0f27c898e9c385882942dbff7fee0ca389a69db0 100644
--- a/src/multiset.c
+++ b/src/multiset.c
@@ -1333,14 +1333,45 @@ union msnode *low_multiset_find_eq (struct multiset *l, struct svalue *key)
 
       if (msd->cmp_less.type == T_INT) {
 	struct svalue tmp;
-	LOW_RB_FIND (
-	  node,
-	  {
+	if (!(msd->ind_types & (BIT_OBJECT | BIT_FUNCTION))) {
+	  /* Can assume an internal order which defines a total order
+	   * for all values. */
+	  LOW_RB_FIND (
+	    node,
+	    {
+	      low_use_multiset_index (RBNODE (node), tmp);
+	      assert (!IS_DESTRUCTED (&tmp));
+	      INTERNAL_CMP (key, &tmp, cmp_res);
+	      assert (cmp_res != CMPFUN_UNORDERED);
+	    },
+	    node = NULL, ;, node = NULL);
+	}
+
+	else {
+	  /* Find the biggest node less or order-wise equal to key. */
+	  LOW_RB_FIND_NEQ (
+	    node,
+	    {
+	      low_use_multiset_index (RBNODE (node), tmp);
+	      if (IS_DESTRUCTED (&tmp)) goto index_destructed;
+	      INTERNAL_CMP (key, &tmp, cmp_res);
+	      if (!cmp_res) cmp_res = 1;
+	      /* Note: CMPFUN_UNORDERED > 0 - treated as equal. */
+	    },
+	    {},			/* Got less or equal or unordered. */
+	    {node = node->prev;}); /* Got greater - step back one. */
+
+	  /* Step backwards until a less or really equal node is found. */
+	  for (; node; node = rb_prev (node)) {
+	    int cmp_res;
 	    low_use_multiset_index (RBNODE (node), tmp);
 	    if (IS_DESTRUCTED (&tmp)) goto index_destructed;
-	    INTERNAL_CMP (key, &tmp, cmp_res);
-	  },
-	  node = NULL, ;, node = NULL);
+	    if (is_eq (&tmp, key)) break;
+	    INTERNAL_CMP (&tmp, key, cmp_res);
+	    /* Note: CMPFUN_UNORDERED > 0 - treated as equal. */
+	    if (cmp_res < 0) {node = NULL; break;}
+	  }
+	}
       }
 
       else {
@@ -1459,6 +1490,7 @@ static enum find_types low_multiset_find_le_gt (
 	  /* TODO: Use special variant of set_svalue_cmpfun so we
 	   * don't have to copy the index svalues. */
 	  INTERNAL_CMP (key, &tmp, cmp_res);
+	  /* Note: CMPFUN_UNORDERED > 0 - treated as equal. */
 	  cmp_res = cmp_res >= 0 ? 1 : -1;
 	},
 	{*found = RBNODE (node); find_type = FIND_LESS; goto done;},
@@ -1526,8 +1558,9 @@ static enum find_types low_multiset_find_lt_ge (
 	  }
 	  /* TODO: Use special variant of set_svalue_cmpfun so we
 	   * don't have to copy the index svalues. */
-	  INTERNAL_CMP (key, &tmp, cmp_res);
-	  cmp_res = cmp_res <= 0 ? -1 : 1;
+	  INTERNAL_CMP (&tmp, key, cmp_res);
+	  /* Note: CMPFUN_UNORDERED > 0 - treated as equal. */
+	  cmp_res = cmp_res >= 0 ? -1 : 1;
 	},
 	{*found = RBNODE (node); find_type = FIND_LESS; goto done;},
 	{*found = RBNODE (node); find_type = FIND_GREATER; goto done;});
@@ -2055,23 +2088,82 @@ static enum find_types low_multiset_track_eq (
 
   if (msd->cmp_less.type == T_INT) {
     struct svalue tmp;
-    LOW_RB_TRACK (
-      rbstack, node,
-      {
+    if (!(msd->ind_types & (BIT_OBJECT | BIT_FUNCTION))) {
+      /* Can assume an internal order which defines a total order for
+       * all values. */
+      LOW_RB_TRACK (
+	rbstack, node,
+	{
+	  low_use_multiset_index (RBNODE (node), tmp);
+	  assert (!IS_DESTRUCTED (&tmp));
+	  /* TODO: Use special variant of set_svalue_cmpfun so we don't
+	   * have to copy the index svalues. */
+	  INTERNAL_CMP (key, &tmp, cmp_res);
+	  assert (cmp_res != CMPFUN_UNORDERED);
+	},
+	{find_type = FIND_LESS; goto done;},
+	{find_type = FIND_EQUAL; goto done;},
+	{find_type = FIND_GREATER; goto done;});
+      /* NOT REACHED */
+    }
+
+    else {
+      /* Find the biggest node less or order-wise equal to key. */
+      struct rb_node_hdr *found_node;
+      int step_count;
+
+      LOW_RB_TRACK_NEQ (
+	rbstack, node,
+	{
+	  low_use_multiset_index (RBNODE (node), tmp);
+	  if (IS_DESTRUCTED (&tmp)) {
+	    UNSET_ONERROR (uwp);
+	    *track = rbstack;
+	    return FIND_DESTRUCTED;
+	  }
+	  INTERNAL_CMP (key, &tmp, cmp_res);
+	  if (!cmp_res) cmp_res = 1;
+	  /* Note: CMPFUN_UNORDERED > 0 - treated as equal. */
+	}, {
+	  find_type = FIND_LESS;
+	  found_node = node;
+	  step_count = 0;
+	}, {
+	  find_type = FIND_GREATER;
+	  found_node = node;
+	  node = node->prev;
+	  step_count = 1;
+	});
+
+      if (IS_DESTRUCTED (key)) {
+	/* An extra check for a destructed key before entering the loop below,
+	 * lest we might go backwards through the whole multiset. */
+	RBSTACK_FREE (rbstack);
+	UNSET_ONERROR (uwp);
+	*track = rbstack;
+	return FIND_KEY_DESTRUCTED;
+      }
+
+      /* Step backwards until a less or really equal node is found. */
+      while (1) {
+	int cmp_res;
+	if (!node) goto done;
 	low_use_multiset_index (RBNODE (node), tmp);
-	if (IS_DESTRUCTED (&tmp)) {
-	  UNSET_ONERROR (uwp);
-	  *track = rbstack;
-	  return FIND_DESTRUCTED;
-	}
-	/* TODO: Use special variant of set_svalue_cmpfun so we don't
-	 * have to copy the index svalues. */
-	INTERNAL_CMP (key, &tmp, cmp_res);
-      },
-      {find_type = FIND_LESS; goto done;},
-      {find_type = FIND_EQUAL; goto done;},
-      {find_type = FIND_GREATER; goto done;});
-    /* NOT REACHED */
+	if (IS_DESTRUCTED (&tmp)) {find_type = FIND_DESTRUCTED; break;}
+	if (is_eq (&tmp, key)) {find_type = FIND_EQUAL; break;}
+	INTERNAL_CMP (&tmp, key, cmp_res);
+	/* Note: CMPFUN_UNORDERED > 0 - treated as equal. */
+	if (cmp_res < 0) goto done;
+	node = rb_prev (node);
+	step_count++;
+      }
+
+      /* A node was found during stepping. Adjust rbstack. */
+      while (step_count--) LOW_RB_TRACK_PREV (rbstack, found_node);
+#ifdef PIKE_DEBUG
+      if (node != RBSTACK_PEEK (rbstack)) Pike_fatal ("Stack stepping failed.\n");
+#endif
+    }
   }
 
   else {
@@ -2178,7 +2270,9 @@ static enum find_types low_multiset_track_le_gt (
 	}
 	/* TODO: Use special variant of set_svalue_cmpfun so we don't
 	 * have to copy the index svalues. */
-	INTERNAL_CMP (key, low_use_multiset_index (RBNODE (node), tmp), cmp_res);
+	INTERNAL_CMP (key, low_use_multiset_index (RBNODE (node), tmp),
+		      cmp_res);
+	/* Note: CMPFUN_UNORDERED > 0 - treated as equal. */
 	cmp_res = cmp_res >= 0 ? 1 : -1;
       },
       {find_type = FIND_LESS; goto done;},
@@ -2247,10 +2341,12 @@ static enum find_types low_multiset_track_lt_ge (
 	  *track = rbstack;
 	  return FIND_DESTRUCTED;
 	}
-	/* TODO: Use special variant of alpha_svalue_cmpfun so we don't
+	/* TODO: Use special variant of set_svalue_cmpfun so we don't
 	 * have to copy the index svalues. */
-	INTERNAL_CMP (key, low_use_multiset_index (RBNODE (node), tmp), cmp_res);
-	cmp_res = cmp_res <= 0 ? -1 : 1;
+	INTERNAL_CMP (low_use_multiset_index (RBNODE (node), tmp), key,
+		      cmp_res);
+	/* Note: CMPFUN_UNORDERED > 0 - treated as equal. */
+	cmp_res = cmp_res >= 0 ? -1 : 1;
       },
       {find_type = FIND_LESS; goto done;},
       {find_type = FIND_GREATER; goto done;});
@@ -3589,7 +3685,10 @@ PMOD_EXPORT struct multiset *merge_multisets (struct multiset *a,
 	  if (IS_DESTRUCTED (&b_ind)) goto ic_nd_free_b;
 	},
 
-	INTERNAL_CMP (&a_ind, &b_ind, cmp_res);,
+	{
+	  INTERNAL_CMP (&a_ind, &b_ind, cmp_res);
+	  if (cmp_res == CMPFUN_UNORDERED) cmp_res = 0;
+	},
 
 	{			/* Copy m.a_node. */
 	  ALLOC_RES_NODE (m.res, res_msd, new_node);
@@ -3630,7 +3729,10 @@ PMOD_EXPORT struct multiset *merge_multisets (struct multiset *a,
 	  if (IS_DESTRUCTED (&b_ind)) goto ic_da_free_b;
 	},
 
-	INTERNAL_CMP (&a_ind, &b_ind, cmp_res);,
+	{
+	  INTERNAL_CMP (&a_ind, &b_ind, cmp_res);
+	  if (cmp_res == CMPFUN_UNORDERED) cmp_res = 0;
+	},
 
 	{			/* Copy m.a_node. */
 	  new_node = m.a_node;
@@ -5045,7 +5147,7 @@ void check_multiset (struct multiset *l, int safe)
 	    nextpos = MSNODE2OFF (msd, next);
 	    /* FIXME: Handle destructed index in node. */
 	    INTERNAL_CMP (low_use_multiset_index (node, tmp1), &tmp2, cmp_res);
-	    if (cmp_res > 0)
+	    if (cmp_res > 0 && cmp_res != CMPFUN_UNORDERED)
 	      Pike_fatal ("Order failure in multiset data with internal order.\n");
 
 	    if (l->msd != msd) {
diff --git a/src/testsuite.in b/src/testsuite.in
index 82a79048cd9802501d59467d36fbfbcf8f3a9b0a..b49fc839b999670194ede548ede343f8c2d5ea16 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -5378,6 +5378,36 @@ test_any([[multiset m=(<>);int e;
   return -1;
 ]],-1)
 
+test_any_equal([[
+  class X (float i)
+  {
+    protected int `< (X o) {return i < o->i;}
+    protected int id = ++all_constants()->cnt;
+    protected string _sprintf() {return "X(" + i + ")[" + id + "]";}
+  };
+  X x1 = X(1.0), x2 = X(1.0);
+  multiset m = (<x1, X(2.0), X(3.0)>);
+  m[x2] = 1;
+  add_constant ("cnt");
+  return ({m[x1], m[x2], m[X(0.5)]});
+]], [[({1, 1, 0})]])
+
+test_any_equal([[
+  class X (float i)
+  {
+    protected int `< (X o) {return i < o->i;}
+    protected int id = ++all_constants()->cnt;
+    protected string _sprintf() {return "X(" + i + ")[" + id + "]";}
+  };
+  X x1 = X(1.0), x2 = X(1.0);
+  multiset m = (<x1, X(2.0), X(3.0)>);
+  m[x2] = 1;
+  add_constant ("cnt");
+  return ({(m[x1] = 1, sizeof (m)),
+	   (m[x2] = 1, sizeof (m)),
+	   (m[X(0.5)] = 1, sizeof (m))});
+]], [[({4, 4, 5})]])
+
 test_eq([[sizeof(mtest_m2)]],sizeof(mtest_i2))
 test_any([[int e;multiset q=(<>),p=(<>); for(e=0;e<1000;e++) { p[reverse(e)]=1; q+=(<reverse(e)>); if(!equal(sort(indices(p)),sort(indices(q)))) return 0; } return 1;]],1)