diff --git a/glnx-macros.h b/glnx-macros.h
index cee068d4fb41bf2ca51d29105901b2666432a639..b5127b74fed30236a1f20ffa73b83b5af6450d6e 100644
--- a/glnx-macros.h
+++ b/glnx-macros.h
@@ -146,9 +146,10 @@ G_BEGIN_DECLS
  * All variables are scoped within the loop. You may use the `it` variable as
  * usual, e.g. to remove an element using g_hash_table_iter_remove(&it). There
  * are shorter variants for the more common cases where you do not need access
- * to the iterator or to values:
+ * to the iterator or to keys/values:
  *
  *   GLNX_HASH_TABLE_FOREACH (table, const char*, str) { ... }
+ *   GLNX_HASH_TABLE_FOREACH_V (table, MyData*, data) { ... }
  *   GLNX_HASH_TABLE_FOREACH_KV (table, const char*, str, MyData*, data) { ... }
  *
  */
@@ -163,6 +164,14 @@ G_BEGIN_DECLS
          _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \
          _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), kt, k, vt, v)
 
+/* Variant of GLNX_HASH_TABLE_FOREACH_KV which omits unpacking keys. */
+#define GLNX_HASH_TABLE_FOREACH_V(ht, vt, v) \
+    _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \
+         _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \
+         _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), \
+         gpointer, _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_v_), \
+         vt, v)
+
 /* Variant of GLNX_HASH_TABLE_FOREACH_KV which omits unpacking vals. */
 #define GLNX_HASH_TABLE_FOREACH(ht, kt, k) \
     _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \
diff --git a/tests/test-libglnx-macros.c b/tests/test-libglnx-macros.c
index 2a115fca66119bc5536d2cc916bcc6dc871a2f3d..ffde8fae202ff3d80589c08b9d17ee18e06beaa3 100644
--- a/tests/test-libglnx-macros.c
+++ b/tests/test-libglnx-macros.c
@@ -90,6 +90,14 @@ test_hash_table_foreach (void)
       i++;
     }
   g_assert_cmpuint (i, ==, 2);
+
+  i = 0;
+  GLNX_HASH_TABLE_FOREACH_V (table, const char*, val)
+    {
+      g_assert_cmpstr (val, ==, vals[i]);
+      i++;
+    }
+  g_assert_cmpuint (i, ==, 2);
 }
 
 int main (int argc, char **argv)