diff --git a/include/expression.h b/include/expression.h
index f0ba6fc..8158579 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -309,6 +309,7 @@ struct expr {
 			enum nft_ng_types	type;
 			uint32_t		mod;
 			uint32_t		offset;
+			struct expr		*ng_map;
 		} numgen;
 		struct {
 			/* EXPR_HASH */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 517a39a..8612fe1 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1382,6 +1382,8 @@ enum nft_trace_types {
  * @NFTA_NG_MODULUS: maximum counter value (NLA_U32)
  * @NFTA_NG_TYPE: operation type (NLA_U32)
  * @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32)
+ * @NFTA_NG_SET_NAME: name of the map to lookup (NLA_STRING)
+ * @NFTA_NG_SET_ID: if of the map (NLA_U32)
  */
 enum nft_ng_attributes {
 	NFTA_NG_UNSPEC,
@@ -1389,6 +1391,8 @@ enum nft_ng_attributes {
 	NFTA_NG_MODULUS,
 	NFTA_NG_TYPE,
 	NFTA_NG_OFFSET,
+	NFTA_NG_SET_NAME,
+	NFTA_NG_SET_ID,
 	__NFTA_NG_MAX
 };
 #define NFTA_NG_MAX	(__NFTA_NG_MAX - 1)
diff --git a/include/numgen.h b/include/numgen.h
index b230620..60eaa37 100644
--- a/include/numgen.h
+++ b/include/numgen.h
@@ -3,6 +3,6 @@
 
 extern struct expr *numgen_expr_alloc(const struct location *loc,
 				      enum nft_ng_types type, uint32_t until,
-				      uint32_t offset);
+				      uint32_t offset, struct expr *mappings);
 
 #endif /* NFTABLES_NUMGEN_H */
diff --git a/src/expression.c b/src/expression.c
index e698b14..53393ec 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -945,7 +945,8 @@ static void map_expr_print(const struct expr *expr, struct output_ctx *octx)
 
 static void map_expr_clone(struct expr *new, const struct expr *expr)
 {
-	new->map      = expr_clone(expr->map);
+	if (expr->map)
+		new->map = expr_clone(expr->map);
 	new->mappings = expr_clone(expr->mappings);
 }
 
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 2126cf2..a270a92 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -668,13 +668,27 @@ static void netlink_parse_numgen(struct netlink_parse_ctx *ctx,
 {
 	enum nft_registers dreg;
 	uint32_t type, until, offset;
-	struct expr *expr;
+	const char *name;
+	struct expr *expr, *right, *map_expr = NULL;
+	struct set *map;
 
 	type  = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_TYPE);
 	until = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_MODULUS);
 	offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_OFFSET);
 
-	expr = numgen_expr_alloc(loc, type, until, offset);
+	name = nftnl_expr_get_str(nle, NFTNL_EXPR_NG_SET_NAME);
+	if (name != NULL) {
+		map  = set_lookup(ctx->table, name);
+		if (map == NULL) {
+			return netlink_error(ctx, loc,
+					"Unknown map '%s' in numgen expression",
+					name);
+		}
+		right = set_ref_expr_alloc(loc, map);
+		map_expr = map_expr_alloc(loc, NULL, right);
+	}
+
+	expr = numgen_expr_alloc(loc, type, until, offset, map_expr);
 	dreg = netlink_parse_register(nle, NFTNL_EXPR_NG_DREG);
 	netlink_set_register(ctx, dreg, expr);
 }
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 6c49969..6f8fdc7 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -218,6 +218,14 @@ static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx,
 	nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_TYPE, expr->numgen.type);
 	nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_MODULUS, expr->numgen.mod);
 	nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_OFFSET, expr->numgen.offset);
+
+	if (expr->numgen.ng_map) {
+		nftnl_expr_set_str(nle, NFTNL_EXPR_NG_SET_NAME,
+				   expr->numgen.ng_map->mappings->identifier);
+		nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_SET_ID,
+				   expr->numgen.ng_map->mappings->set->handle.set_id);
+	}
+
 	nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
diff --git a/src/numgen.c b/src/numgen.c
index aa6da49..cf35a407 100644
--- a/src/numgen.c
+++ b/src/numgen.c
@@ -35,13 +35,18 @@ static void numgen_expr_print(const struct expr *expr, struct output_ctx *octx)
 		  expr->numgen.mod);
 	if (expr->numgen.offset)
 		nft_print(octx, " offset %u", expr->numgen.offset);
+	if (expr->numgen.ng_map) {
+		nft_print(octx, " ");
+		expr_print(expr->numgen.ng_map->mappings, octx);
+	}
 }
 
 static bool numgen_expr_cmp(const struct expr *e1, const struct expr *e2)
 {
 	return e1->numgen.type == e2->numgen.type &&
 	       e1->numgen.mod == e2->numgen.mod &&
-	       e1->numgen.offset == e2->numgen.offset;
+	       e1->numgen.offset == e2->numgen.offset &&
+	       expr_cmp(e1->numgen.ng_map, e2->numgen.ng_map);
 }
 
 static void numgen_expr_clone(struct expr *new, const struct expr *expr)
@@ -49,6 +54,8 @@ static void numgen_expr_clone(struct expr *new, const struct expr *expr)
 	new->numgen.type = expr->numgen.type;
 	new->numgen.mod = expr->numgen.mod;
 	new->numgen.offset = expr->numgen.offset;
+	if (expr->numgen.ng_map)
+		new->numgen.ng_map = expr_clone(expr->numgen.ng_map);
 }
 
 static const struct expr_ops numgen_expr_ops = {
@@ -61,7 +68,7 @@ static const struct expr_ops numgen_expr_ops = {
 
 struct expr *numgen_expr_alloc(const struct location *loc,
 			       enum nft_ng_types type, uint32_t mod,
-			       uint32_t offset)
+			       uint32_t offset, struct expr *mappings)
 {
 	struct expr *expr;
 
@@ -70,6 +77,8 @@ struct expr *numgen_expr_alloc(const struct location *loc,
 	expr->numgen.type  = type;
 	expr->numgen.mod   = mod;
 	expr->numgen.offset = offset;
+	if (mappings)
+		expr->numgen.ng_map = mappings;
 
 	return expr;
 }
diff --git a/src/parser_bison.y b/src/parser_bison.y
index f546b9e..4a010e6 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -660,8 +660,8 @@ int nft_lex(void *, void *, void *);
 %type <expr>			arp_hdr_expr
 %destructor { expr_free($$); }	arp_hdr_expr
 %type <val>			arp_hdr_field
-%type <expr>			ip_hdr_expr	icmp_hdr_expr		numgen_expr	hash_expr
-%destructor { expr_free($$); }	ip_hdr_expr	icmp_hdr_expr		numgen_expr	hash_expr
+%type <expr>			ip_hdr_expr	icmp_hdr_expr		numgen_expr	numgen_map_expr		hash_expr
+%destructor { expr_free($$); }	ip_hdr_expr	icmp_hdr_expr		numgen_expr	numgen_map_expr		hash_expr
 %type <val>			ip_hdr_field	icmp_hdr_field
 %type <expr>			ip6_hdr_expr    icmp6_hdr_expr
 %destructor { expr_free($$); }	ip6_hdr_expr	icmp6_hdr_expr
@@ -3509,12 +3509,20 @@ numgen_type		:	INC		{ $$ = NFT_NG_INCREMENTAL; }
 			|	RANDOM		{ $$ = NFT_NG_RANDOM; }
 			;
 
-numgen_expr		:	NUMGEN	numgen_type	MOD	NUM	offset_opt
+numgen_map_expr		:	/* empty */	{ $$ = NULL; }
+			|	symbol_expr
 			{
-				$$ = numgen_expr_alloc(&@$, $2, $4, $5);
+				$$ = map_expr_alloc(&@$, NULL, $1);
+				$$->flags  |= NFT_SET_OBJECT;
 			}
 			;
 
+numgen_expr		:	NUMGEN	numgen_type	MOD	NUM	offset_opt	numgen_map_expr
+			{
+				$$ = numgen_expr_alloc(&@$, $2, $4, $5, $6);
+                        }
+			;
+
 hash_expr		:	JHASH		expr	MOD	NUM	SEED	NUM	offset_opt
 			{
 				$$ = hash_expr_alloc(&@$, $4, true, $6, $7, NFT_HASH_JENKINS);
