diff --git a/src/python/src/grpc/_adapter/_c/types.h b/src/python/src/grpc/_adapter/_c/types.h
index e189ae25660f2e356f5d404c13e9ad847f9168bd..3449f0643f79c5964d68f1ee513e6a2f49782616 100644
--- a/src/python/src/grpc/_adapter/_c/types.h
+++ b/src/python/src/grpc/_adapter/_c/types.h
@@ -241,10 +241,10 @@ double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec);
 gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds);
 
 /* Returns true on success, false on failure. */
-int pygrpc_cast_pylist_to_send_metadata(
-    PyObject *pylist, grpc_metadata **metadata, size_t *count);
+int pygrpc_cast_pyseq_to_send_metadata(
+    PyObject *pyseq, grpc_metadata **metadata, size_t *count);
 /* Returns a metadata array as a Python object on success, else NULL. */
-PyObject *pygrpc_cast_metadata_array_to_pylist(grpc_metadata_array metadata);
+PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata);
 
 /* Transliterate from a list of python channel arguments (2-tuples of string
    and string|integer|None) to a grpc_channel_args object. The strings placed
diff --git a/src/python/src/grpc/_adapter/_c/utility.c b/src/python/src/grpc/_adapter/_c/utility.c
index a433f26d769163ae0145f5f6017279196872cf49..480a720c21fa54e4ef368bde5138866c9ca21060 100644
--- a/src/python/src/grpc/_adapter/_c/utility.c
+++ b/src/python/src/grpc/_adapter/_c/utility.c
@@ -32,6 +32,7 @@
  */
 
 #include <math.h>
+#include <string.h>
 
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
@@ -118,7 +119,7 @@ PyObject *pygrpc_consume_event(grpc_event event) {
           tag->request_call_details.method, tag->request_call_details.host,
           pygrpc_cast_gpr_timespec_to_double(tag->request_call_details.deadline),
           GRPC_OP_RECV_INITIAL_METADATA,
-          pygrpc_cast_metadata_array_to_pylist(tag->request_metadata), Py_None,
+          pygrpc_cast_metadata_array_to_pyseq(tag->request_metadata), Py_None,
           Py_None, Py_None, Py_None,
           event.success ? Py_True : Py_False);
     } else {
@@ -172,7 +173,7 @@ int pygrpc_produce_op(PyObject *op, grpc_op *result) {
   c_op.flags = 0;
   switch (type) {
   case GRPC_OP_SEND_INITIAL_METADATA:
-    if (!pygrpc_cast_pylist_to_send_metadata(
+    if (!pygrpc_cast_pyseq_to_send_metadata(
             PyTuple_GetItem(op, INITIAL_METADATA_INDEX),
             &c_op.data.send_initial_metadata.metadata,
             &c_op.data.send_initial_metadata.count)) {
@@ -190,7 +191,7 @@ int pygrpc_produce_op(PyObject *op, grpc_op *result) {
     /* Don't need to fill in any other fields. */
     break;
   case GRPC_OP_SEND_STATUS_FROM_SERVER:
-    if (!pygrpc_cast_pylist_to_send_metadata(
+    if (!pygrpc_cast_pyseq_to_send_metadata(
             PyTuple_GetItem(op, TRAILING_METADATA_INDEX),
             &c_op.data.send_status_from_server.trailing_metadata,
             &c_op.data.send_status_from_server.trailing_metadata_count)) {
@@ -247,8 +248,16 @@ int pygrpc_produce_op(PyObject *op, grpc_op *result) {
 }
 
 void pygrpc_discard_op(grpc_op op) {
+  size_t i;
   switch(op.op) {
   case GRPC_OP_SEND_INITIAL_METADATA:
+    /* Whenever we produce send-metadata, we allocate new strings (to handle
+       arbitrary sequence input as opposed to just lists or just tuples). We
+       thus must free those elements. */
+    for (i = 0; i < op.data.send_initial_metadata.count; ++i) {
+      gpr_free((void *)op.data.send_initial_metadata.metadata[i].key);
+      gpr_free((void *)op.data.send_initial_metadata.metadata[i].value);
+    }
     gpr_free(op.data.send_initial_metadata.metadata);
     break;
   case GRPC_OP_SEND_MESSAGE:
@@ -258,6 +267,16 @@ void pygrpc_discard_op(grpc_op op) {
     /* Don't need to free any fields. */
     break;
   case GRPC_OP_SEND_STATUS_FROM_SERVER:
+    /* Whenever we produce send-metadata, we allocate new strings (to handle
+       arbitrary sequence input as opposed to just lists or just tuples). We
+       thus must free those elements. */
+    for (i = 0; i < op.data.send_status_from_server.trailing_metadata_count;
+         ++i) {
+      gpr_free(
+          (void *)op.data.send_status_from_server.trailing_metadata[i].key);
+      gpr_free(
+          (void *)op.data.send_status_from_server.trailing_metadata[i].value);
+    }
     gpr_free(op.data.send_status_from_server.trailing_metadata);
     gpr_free((char *)op.data.send_status_from_server.status_details);
     break;
@@ -419,31 +438,41 @@ void pygrpc_discard_channel_args(grpc_channel_args args) {
   gpr_free(args.args);
 }
 
-int pygrpc_cast_pylist_to_send_metadata(
-    PyObject *pylist, grpc_metadata **metadata, size_t *count) {
+int pygrpc_cast_pyseq_to_send_metadata(
+    PyObject *pyseq, grpc_metadata **metadata, size_t *count) {
   size_t i;
   Py_ssize_t value_length;
-  *count = PyList_Size(pylist);
+  char *key;
+  char *value;
+  if (!PySequence_Check(pyseq)) {
+    return 0;
+  }
+  *count = PySequence_Size(pyseq);
   *metadata = gpr_malloc(sizeof(grpc_metadata) * *count);
   for (i = 0; i < *count; ++i) {
-    if (!PyArg_ParseTuple(
-        PyList_GetItem(pylist, i), "ss#",
-        &(*metadata)[i].key, &(*metadata)[i].value, &value_length)) {
+    PyObject *item = PySequence_GetItem(pyseq, i);
+    if (!PyArg_ParseTuple(item, "ss#", &key, &value, &value_length)) {
+      Py_DECREF(item);
       gpr_free(*metadata);
       *count = 0;
       *metadata = NULL;
       return 0;
+    } else {
+      (*metadata)[i].key = gpr_strdup(key);
+      (*metadata)[i].value = gpr_malloc(value_length);
+      memcpy((void *)(*metadata)[i].value, value, value_length);
+      Py_DECREF(item);
     }
     (*metadata)[i].value_length = value_length;
   }
   return 1;
 }
 
-PyObject *pygrpc_cast_metadata_array_to_pylist(grpc_metadata_array metadata) {
-  PyObject *result = PyList_New(metadata.count);
+PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata) {
+  PyObject *result = PyTuple_New(metadata.count);
   size_t i;
   for (i = 0; i < metadata.count; ++i) {
-    PyList_SetItem(
+    PyTuple_SetItem(
         result, i, Py_BuildValue(
             "ss#", metadata.metadata[i].key, metadata.metadata[i].value,
             (Py_ssize_t)metadata.metadata[i].value_length));