diff --git a/perxis-proto b/perxis-proto
index 2e4728f6f3d5d63dcb9d5548b17af9efce605280..d05d75325479800baef608bcde55c46b42b019e0 160000
--- a/perxis-proto
+++ b/perxis-proto
@@ -1 +1 @@
-Subproject commit 2e4728f6f3d5d63dcb9d5548b17af9efce605280
+Subproject commit d05d75325479800baef608bcde55c46b42b019e0
diff --git a/pkg/schema/localizer/localizer_test.go b/pkg/schema/localizer/localizer_test.go
index ded5628dcdd2ec0686243a0da08ef8612d498777..fffda4b78c98f5f7a4ee6e10fcb3007297598123 100644
--- a/pkg/schema/localizer/localizer_test.go
+++ b/pkg/schema/localizer/localizer_test.go
@@ -762,6 +762,7 @@ func TestLocalizer_ExtractTranslations(t *testing.T) {
 
 	s := schema.New(
 		"a", field.String(),
+		"b", field.String(),
 	)
 
 	tests := []struct {
@@ -877,7 +878,7 @@ func TestLocalizer_ExtractTranslations(t *testing.T) {
 		{
 			name:         "Extract fallback with same",
 			data:         map[string]interface{}{"a": "aaa"},
-			translations: map[string]map[string]interface{}{"ru": {"a": "aaa"}, "en": {"a": "aaa"}},
+			translations: map[string]map[string]interface{}{"ru": {"a": "aaa"}, "en": {"a": "aaa", "b": "bbb"}},
 			cfg: Config{
 				LocaleID: "ru",
 				Schema:   s,
diff --git a/pkg/schema/walk/walk.go b/pkg/schema/walk/walk.go
index 73bd1f9258d17d33fa4350a18a835e786f1082b5..ab11ebe6ee0614a702c4c2a0f5747afe0e994ea4 100644
--- a/pkg/schema/walk/walk.go
+++ b/pkg/schema/walk/walk.go
@@ -120,6 +120,7 @@ func (m *Walker) datawalk(w *WalkContext) (err error) {
 
 		fields := p.GetFields(true)
 
+		var objChanged bool
 		for k := range keys {
 			f, ok := fields[k]
 			if !ok {
@@ -144,13 +145,16 @@ func (m *Walker) datawalk(w *WalkContext) (err error) {
 			}
 
 			if wc.Changed {
+				objChanged = true
 				w.Changed = true
 			}
 		}
-		if len(res) > 0 {
+
+		if objChanged || len(res) != len(d) { // in generic merge unknown fields are removed but change is not set
 			w.Dst = res
 		}
 
+
 	case *field.ArrayParameters:
 		d, _ := w.Dst.([]interface{})
 		s, _ := w.Src.([]interface{})
@@ -175,7 +179,6 @@ func (m *Walker) datawalk(w *WalkContext) (err error) {
 				w.Changed = true
 			}
 		}
-
 	}
 
 	return
diff --git a/pkg/schema/walk/walk_test.go b/pkg/schema/walk/walk_test.go
index 3fd01bd577c3fe16abb1cae7b2e9785e0edc659c..be33aa2fed74abb6493cd9aa5dd2b3470847c3d8 100644
--- a/pkg/schema/walk/walk_test.go
+++ b/pkg/schema/walk/walk_test.go
@@ -56,10 +56,10 @@ func TestWalker_DataWalk(t *testing.T) {
 					"a": "src_obj1_a",
 					"b": "src_obj1_b",
 					"obj2": map[string]interface{}{
-						"a": "dst_obj1_obj2_a",
+						"a": "src_obj1_obj2_a",
 					},
 					"obj3": map[string]interface{}{
-						"e": "dst_obj1_obj3_e",
+						"e": "src_obj1_obj3_e",
 					},
 				},
 				"inline_str_1": "src_inline_1",
@@ -109,10 +109,10 @@ func TestWalker_DataWalk(t *testing.T) {
 					"a": "src_obj1_a",
 					"b": "src_obj1_b",
 					"obj2": map[string]interface{}{
-						"a": "dst_obj1_obj2_a",
+						"a": "src_obj1_obj2_a",
 					},
 					"obj3": map[string]interface{}{
-						"e": "dst_obj1_obj3_e",
+						"e": "src_obj1_obj3_e",
 					},
 				},
 				"inline_str_1": "src_inline_1",
@@ -162,10 +162,10 @@ func TestWalker_DataWalk(t *testing.T) {
 					"a": "src_obj1_a",
 					"b": "src_obj1_b",
 					"obj2": map[string]interface{}{
-						"a": "dst_obj1_obj2_a",
+						"a": "src_obj1_obj2_a",
 					},
 					"obj3": map[string]interface{}{
-						"e": "dst_obj1_obj3_e",
+						"e": "src_obj1_obj3_e",
 					},
 				},
 				"inline_str_1": "src_inline_1",
@@ -179,10 +179,10 @@ func TestWalker_DataWalk(t *testing.T) {
 					"a": "src_obj1_a",
 					"b": "src_obj1_b",
 					"obj2": map[string]interface{}{
-						"a": "dst_obj1_obj2_a",
+						"a": "src_obj1_obj2_a",
 					},
 					"obj3": map[string]interface{}{
-						"e": "dst_obj1_obj3_e",
+						"e": "src_obj1_obj3_e",
 					},
 				},
 				"inline_str_1": "src_inline_1",
@@ -196,10 +196,10 @@ func TestWalker_DataWalk(t *testing.T) {
 					"a": "src_obj1_a",
 					"b": "src_obj1_b",
 					"obj2": map[string]interface{}{
-						"a": "dst_obj1_obj2_a",
+						"a": "src_obj1_obj2_a",
 					},
 					"obj3": map[string]interface{}{
-						"e": "dst_obj1_obj3_e",
+						"e": "src_obj1_obj3_e",
 					},
 				},
 				"inline_str_1": "src_inline_1",
@@ -208,6 +208,220 @@ func TestWalker_DataWalk(t *testing.T) {
 			},
 			false, false,
 		},
+		{"keep src nil",
+			&WalkConfig{
+				Fields: map[string]FieldConfig{
+					"a":            {Fn: KeepSrc},
+					"obj1.a":       {Fn: KeepSrc},
+					"inline_str_1": {Fn: KeepSrc},
+					"slice.1":      {Fn: KeepSrc},
+				},
+			},
+			map[string]interface{}{
+				"b": "src_b",
+				"obj1": map[string]interface{}{
+					"b": "src_obj1_b",
+					"obj2": map[string]interface{}{
+						"a": "scr_obj1_obj2_a",
+					},
+					"obj3": map[string]interface{}{
+						"e": "src_obj1_obj3_e",
+					},
+				},
+				"slice": []interface{}{"src_s1"},
+			},
+			map[string]interface{}{
+				"a": "dst_a",
+				"b": "dst_b",
+				"obj1": map[string]interface{}{
+					"a": "dst_obj1_a",
+					"b": "dst_obj1_b",
+					"obj2": map[string]interface{}{
+						"a": "dst_obj1_obj2_a",
+					},
+					"obj3": map[string]interface{}{
+						"e": "dst_obj1_obj3_e",
+					},
+				},
+				"inline_str_1": "dst_inline_1",
+				"inline_str_2": "dst_inline_2",
+				"slice":        []interface{}{"dst_s1", "dst_s2"},
+			},
+			map[string]interface{}{
+				"b": "dst_b",
+				"obj1": map[string]interface{}{
+					"b": "dst_obj1_b",
+					"obj2": map[string]interface{}{
+						"a": "dst_obj1_obj2_a",
+					},
+					"obj3": map[string]interface{}{
+						"e": "dst_obj1_obj3_e",
+					},
+				},
+				"inline_str_2": "dst_inline_2",
+				"slice":        []interface{}{"dst_s1", nil},
+			},
+			true, false,
+		},
+		{"keep src nil #2",
+			&WalkConfig{
+				Fields: map[string]FieldConfig{
+					"a": {Fn: KeepSrc},
+				},
+			},
+			map[string]interface{}{},
+			map[string]interface{}{
+				"a": "dst_a",
+			},
+			map[string]interface{}{},
+			true, false,
+		},
+		{"keep src ni #3",
+			&WalkConfig{
+				Fields: map[string]FieldConfig{
+					"obj1":  {Fn: KeepSrc},
+					"slice": {Fn: KeepSrc},
+				},
+			},
+			map[string]interface{}{
+				"b": "src_b",
+			},
+			map[string]interface{}{
+				"a": "dst_a",
+				"b": "src_b",
+				"obj1": map[string]interface{}{
+					"a": "src_obj1_a",
+					"b": "src_obj1_b",
+					"obj2": map[string]interface{}{
+						"a": "dst_obj1_obj2_a",
+					},
+					"obj3": map[string]interface{}{
+						"e": "dst_obj1_obj3_e",
+					},
+				},
+				"inline_str_1": "dst_inline_1",
+				"inline_str_2": "dst_inline_2",
+				"slice":        []interface{}{"src_s1", "src_s2"},
+			},
+			map[string]interface{}{
+				"a":            "dst_a",
+				"b":            "src_b",
+				"inline_str_1": "dst_inline_1",
+				"inline_str_2": "dst_inline_2",
+			},
+			true, false,
+		},
+		{"keep src ni #3",
+			&WalkConfig{
+				Fields: map[string]FieldConfig{
+					"obj1.a":    {Fn: KeepSrc},
+					"obj1.b":    {Fn: KeepSrc},
+					"obj1.obj2": {Fn: KeepSrc},
+					"obj1.obj3": {Fn: KeepSrc},
+				},
+			},
+			map[string]interface{}{
+				"b": "src_b",
+			},
+			map[string]interface{}{
+				"a": "dst_a",
+				"b": "src_b",
+				"obj1": map[string]interface{}{
+					"a": "src_obj1_a",
+					"b": "src_obj1_b",
+					"obj2": map[string]interface{}{
+						"a": "dst_obj1_obj2_a",
+					},
+					"obj3": map[string]interface{}{
+						"e": "dst_obj1_obj3_e",
+					},
+				},
+			},
+			map[string]interface{}{
+				"a":    "dst_a",
+				"b":    "src_b",
+				"obj1": map[string]interface{}{},
+			},
+			true, false,
+		},
+		{"remove fields",
+			&WalkConfig{
+				Fields: map[string]FieldConfig{
+					"a":            {Fn: RemoveValue},
+					"obj1.a":       {Fn: RemoveValue},
+					"inline_str_1": {Fn: RemoveValue},
+					"slice.1":      {Fn: RemoveValue},
+				},
+			},
+			map[string]interface{}{},
+			map[string]interface{}{
+				"a": "dst_a",
+				"b": "dst_b",
+				"obj1": map[string]interface{}{
+					"a": "dst_obj1_a",
+					"b": "dst_obj1_b",
+					"obj2": map[string]interface{}{
+						"a": "dst_obj1_obj2_a",
+					},
+					"obj3": map[string]interface{}{
+						"e": "dst_obj1_obj3_e",
+					},
+				},
+				"inline_str_1": "dst_inline_1",
+				"inline_str_2": "dst_inline_2",
+				"slice":        []interface{}{"dst_s1", "dts_s2"},
+			},
+			map[string]interface{}{
+				"b": "dst_b",
+				"obj1": map[string]interface{}{
+					"b": "dst_obj1_b",
+					"obj2": map[string]interface{}{
+						"a": "dst_obj1_obj2_a",
+					},
+					"obj3": map[string]interface{}{
+						"e": "dst_obj1_obj3_e",
+					},
+				},
+				"inline_str_2": "dst_inline_2",
+				"slice":        []interface{}{"dst_s1", nil},
+			},
+			true, false,
+		},
+		{"remove fields #2",
+			&WalkConfig{
+				Fields: map[string]FieldConfig{
+					"obj1":  {Fn: RemoveValue},
+					"slice": {Fn: RemoveValue},
+				},
+			},
+			map[string]interface{}{
+				"b": "src_b",
+			},
+			map[string]interface{}{
+				"a": "dst_a",
+				"b": "src_b",
+				"obj1": map[string]interface{}{
+					"a": "src_obj1_a",
+					"b": "src_obj1_b",
+					"obj2": map[string]interface{}{
+						"a": "dst_obj1_obj2_a",
+					},
+					"obj3": map[string]interface{}{
+						"e": "dst_obj1_obj3_e",
+					},
+				},
+				"inline_str_1": "dst_inline_1",
+				"inline_str_2": "dst_inline_2",
+				"slice":        []interface{}{"src_s1", "src_s2"},
+			},
+			map[string]interface{}{
+				"a":            "dst_a",
+				"b":            "src_b",
+				"inline_str_1": "dst_inline_1",
+				"inline_str_2": "dst_inline_2",
+			},
+			true, false,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {