diff --git a/py/objint.c b/py/objint.c
index 27834b81fde1615a8faf6dc2fe84d2f8c742157f..3a853eab800c1be874b7bb8d69286bac12fee47e 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
 #include <stdint.h>
 #include <assert.h>
 
@@ -9,6 +10,8 @@
 #include "parsenum.h"
 #include "mpz.h"
 #include "objint.h"
+#include "runtime0.h"
+#include "runtime.h"
 
 #if MICROPY_ENABLE_FLOAT
 #include <math.h>
@@ -59,16 +62,20 @@ void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj
     }
 }
 
-// This is called only for non-SMALL_INT
+// This is called for operations on SMALL_INT that are not handled by mp_unary_op
 mp_obj_t int_unary_op(int op, mp_obj_t o_in) {
-    assert(0);
-    return mp_const_none;
+    return MP_OBJ_NULL;
 }
 
-// This is called only for non-SMALL_INT
+// This is called for operations on SMALL_INT that are not handled by mp_binary_op
 mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
-    assert(0);
-    return mp_const_none;
+    if (op == MP_BINARY_OP_MULTIPLY) {
+        if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
+            // multiply is commutative for these types, so delegate to them
+            return mp_binary_op(op, rhs_in, lhs_in);
+        }
+    }
+    return MP_OBJ_NULL;
 }
 
 // This is called only with strings whose value doesn't fit in SMALL_INT
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index e64cc6734f8a8a22919bf53a49310fad86614a79..acbd477a9a601fed30d905b2b1885f479932f836 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -9,6 +9,7 @@
 #include "mpz.h"
 #include "objint.h"
 #include "runtime0.h"
+#include "runtime.h"
 
 #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
 
@@ -57,6 +58,13 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) {
         rhs_val = ((mp_obj_int_t*)rhs_in)->val;
     } else {
+        if (op == MP_BINARY_OP_MULTIPLY) {
+            if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
+                // multiply is commutative for these types, so delegate to them
+                return mp_binary_op(op, rhs_in, lhs_in);
+            }
+        }
+        // unsupported operation/type
         return MP_OBJ_NULL;
     }
 
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 7f12fbcd0f6ff5bbad9f1990e112c19aac601f38..27f77d14b7898d07352c476d4c2d67e09d324e6f 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -11,6 +11,7 @@
 #include "mpz.h"
 #include "objint.h"
 #include "runtime0.h"
+#include "runtime.h"
 
 #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
 
@@ -74,7 +75,13 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
         return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);
 #endif
     } else {
-        // unsupported type
+        if (op == MP_BINARY_OP_MULTIPLY) {
+            if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
+                // multiply is commutative for these types, so delegate to them
+                return mp_binary_op(op, rhs_in, lhs_in);
+            }
+        }
+        // unsupported operation/type
         return MP_OBJ_NULL;
     }