diff --git a/src/evalfunc.c b/src/evalfunc.c
index 533f5b95d..dc056da8b 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -750,7 +750,7 @@ static funcentry_T global_functions[] =
     {"matcharg",	1, 1, FEARG_1,	  ret_list_string, f_matcharg},
     {"matchdelete",	1, 2, FEARG_1,	  ret_number,	f_matchdelete},
     {"matchend",	2, 4, FEARG_1,	  ret_number,	f_matchend},
-    {"matchfuzzy",	2, 2, FEARG_1,	  ret_list_string,	f_matchfuzzy},
+    {"matchfuzzy",	2, 3, FEARG_1,	  ret_list_string,	f_matchfuzzy},
     {"matchlist",	2, 4, FEARG_1,	  ret_list_string, f_matchlist},
     {"matchstr",	2, 4, FEARG_1,	  ret_string,	f_matchstr},
     {"matchstrpos",	2, 4, FEARG_1,	  ret_list_any,	f_matchstrpos},
diff --git a/src/search.c b/src/search.c
index 9572785b7..5e9b42c3d 100644
--- a/src/search.c
+++ b/src/search.c
@@ -4429,7 +4429,11 @@ fuzzy_item_compare(const void *s1, const void *s2)
  * in 'fmatchlist'.
  */
     static void
-match_fuzzy(list_T *strlist, char_u *str, list_T *fmatchlist)
+match_fuzzy(
+	list_T		*strlist,
+	char_u		*str,
+	callback_T	*item_cb,
+	list_T		*fmatchlist)
 {
     long	len;
     fuzzyItem_T	*ptrs;
@@ -4448,18 +4452,40 @@ match_fuzzy(list_T *strlist, char_u *str, list_T *fmatchlist)
     // For all the string items in strlist, get the fuzzy matching score
     FOR_ALL_LIST_ITEMS(strlist, li)
     {
-	int	score;
+	int		score;
+	char_u		*p;
+	typval_T	rettv;
+	typval_T	argv[2];
 
 	ptrs[i].item = li;
 	ptrs[i].score = -9999;
-	// ignore non-string items in the list
-	if (li->li_tv.v_type == VAR_STRING && li->li_tv.vval.v_string != NULL)
-	    if (fuzzy_match(li->li_tv.vval.v_string, str, &score))
+	p = NULL;
+	rettv.v_type = VAR_UNKNOWN;
+	if (li->li_tv.v_type == VAR_STRING)
+	    p = li->li_tv.vval.v_string;
+	else if (li->li_tv.v_type == VAR_DICT && item_cb->cb_name != NULL)
+	{
+	    // for a dict, invoke the supplied callback (if any) to get the
+	    // dict item.
+	    li->li_tv.vval.v_dict->dv_refcount++;
+	    argv[0].v_type = VAR_DICT;
+	    argv[0].vval.v_dict = li->li_tv.vval.v_dict;
+	    argv[1].v_type = VAR_UNKNOWN;
+	    if (call_callback(item_cb, -1, &rettv, 1, argv) != FAIL)
 	    {
-		ptrs[i].score = score;
-		found_match = TRUE;
+		if (rettv.v_type == VAR_STRING)
+		    p = rettv.vval.v_string;
 	    }
+	    dict_unref(li->li_tv.vval.v_dict);
+	}
+
+	if (p != NULL && fuzzy_match(p, str, &score))
+	{
+	    ptrs[i].score = score;
+	    found_match = TRUE;
+	}
 	++i;
+	clear_tv(&rettv);
     }
 
     if (found_match)
@@ -4473,8 +4499,7 @@ match_fuzzy(list_T *strlist, char_u *str, list_T *fmatchlist)
 	{
 	    if (ptrs[i].score == -9999)
 		break;
-	    list_append_string(fmatchlist, ptrs[i].item->li_tv.vval.v_string,
-		    -1);
+	    list_append_tv(fmatchlist, &ptrs[i].item->li_tv);
 	}
     }
 
@@ -4487,6 +4512,10 @@ match_fuzzy(list_T *strlist, char_u *str, list_T *fmatchlist)
     void
 f_matchfuzzy(typval_T *argvars, typval_T *rettv)
 {
+    callback_T	cb;
+
+    CLEAR_POINTER(&cb);
+
     if (argvars[0].v_type != VAR_LIST)
     {
 	emsg(_(e_listreq));
@@ -4500,9 +4529,18 @@ f_matchfuzzy(typval_T *argvars, typval_T *rettv)
 	semsg(_(e_invarg2), tv_get_string(&argvars[1]));
 	return;
     }
+    if (argvars[2].v_type != VAR_UNKNOWN)
+    {
+	cb = get_callback(&argvars[2]);
+	if (cb.cb_name == NULL)
+	    return;
+    }
+
     if (rettv_list_alloc(rettv) == OK)
-	match_fuzzy(argvars[0].vval.v_list, tv_get_string(&argvars[1]),
+	match_fuzzy(argvars[0].vval.v_list, tv_get_string(&argvars[1]), &cb,
 		rettv->vval.v_list);
+
+    free_callback(&cb);
 }
 
 #endif
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index e31b63cc4..922565582 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -2576,6 +2576,14 @@ func Test_matchfuzzy()
   let l = getbufinfo()->map({_, v -> v.name})->matchfuzzy('ndl')
   call assert_equal(1, len(l))
   call assert_match('needle', l[0])
+
+  let l = [{'id' : 5, 'val' : 'crayon'}, {'id' : 6, 'val' : 'camera'}]
+  call assert_equal([{'id' : 6, 'val' : 'camera'}], matchfuzzy(l, 'cam', {v -> v.val}))
+  call assert_equal([], matchfuzzy(l, 'day', {v -> v.val}))
+  call assert_equal([], matchfuzzy(l, 'day', {v -> []}))
+  call assert_equal([], matchfuzzy(l, 'day', {v -> 1}))
+  call assert_fails("let x = matchfuzzy(l, 'day', {a, b -> 1})", 'E119:')
+  call assert_equal([], matchfuzzy(l, 'cam'))
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
