diff --git a/base_rest_datamodel/restapi.py b/base_rest_datamodel/restapi.py
index dc11150f4..449949075 100644
--- a/base_rest_datamodel/restapi.py
+++ b/base_rest_datamodel/restapi.py
@@ -37,7 +37,9 @@ def to_response(self, service, result):
             json = [i.dump() for i in result]
         else:
             json = result.dump()
-        errors = ModelClass.validate(json, many=self._is_list)
+        errors = ModelClass.validate(
+            json, many=self._is_list, unknown=marshmallow.EXCLUDE
+        )
         if errors:
             raise SystemError(_("Invalid Response %s") % errors)
         return json
diff --git a/base_rest_datamodel/tests/__init__.py b/base_rest_datamodel/tests/__init__.py
new file mode 100644
index 000000000..d5006168c
--- /dev/null
+++ b/base_rest_datamodel/tests/__init__.py
@@ -0,0 +1 @@
+from . import test_response
diff --git a/base_rest_datamodel/tests/test_response.py b/base_rest_datamodel/tests/test_response.py
new file mode 100644
index 000000000..0424324f5
--- /dev/null
+++ b/base_rest_datamodel/tests/test_response.py
@@ -0,0 +1,76 @@
+# Copyright 2021 Wakari SRL
+# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
+import marshmallow
+import mock
+
+from odoo.addons.base_rest_datamodel import restapi
+from odoo.addons.datamodel import fields
+from odoo.addons.datamodel.core import Datamodel
+from odoo.addons.datamodel.tests import common
+
+
+class TestDataModel(common.DatamodelRegistryCase):
+    def _to_response(self, instance):
+        restapi_datamodel = restapi.Datamodel(instance._name)
+        mock_service = mock.Mock()
+        mock_service.env = self.env
+        return restapi_datamodel.to_response(mock_service, instance)
+
+    def test_to_response(self):
+        class Datamodel1(Datamodel):
+            _name = "datamodel1"
+
+            name = fields.String(required=True, allow_none=False)
+
+        Datamodel1._build_datamodel(self.datamodel_registry)
+        instance = self.env.datamodels["datamodel1"](name="Instance 1")
+        res = self._to_response(instance)
+        self.assertEqual(res["name"], instance.name)
+
+    def test_to_response_dump_only(self):
+        class Datamodel2(Datamodel):
+            _name = "datamodel2"
+
+            name = fields.String(required=True, allow_none=False, dump_only=True)
+
+        Datamodel2._build_datamodel(self.datamodel_registry)
+        schema = self.env.datamodels["datamodel2"].get_schema()
+        self.assertEqual(schema.unknown, "raise")
+        msg = r"{'name': \['Unknown field.'\]}"
+        with self.assertRaisesRegex(marshmallow.exceptions.ValidationError, msg):
+            # confirmation that "name" cannot be loaded
+            self.env.datamodels["datamodel2"].load({"name": "Failure"})
+        instance = self.env.datamodels["datamodel2"](name="Instance 2")
+        res = self._to_response(instance)
+        self.assertEqual(res["name"], instance.name)
+        # schema 'unknown' is back to "raise"
+        self.assertEqual(schema.unknown, "raise")
+
+    def test_to_response_dump_only_nested(self):
+        class Datamodel3(Datamodel):
+            _name = "datamodel3"
+
+            child = fields.NestedModel("nested_datamodel")
+
+        class NestedDatamodel(Datamodel):
+            _name = "nested_datamodel"
+
+            name = fields.String(required=True, allow_none=False, dump_only=True)
+
+        NestedDatamodel._build_datamodel(self.datamodel_registry)
+        Datamodel3._build_datamodel(self.datamodel_registry)
+        for datamodel_name in ("datamodel3", "nested_datamodel"):
+            schema = self.env.datamodels[datamodel_name].get_schema()
+            self.assertEqual(schema.unknown, "raise")
+        msg = r"{'name': \['Unknown field.'\]}"
+        with self.assertRaisesRegex(marshmallow.exceptions.ValidationError, msg):
+            # confirmation that child "name" cannot be loaded
+            self.env.datamodels["datamodel3"].load({"child": {"name": "Failure"}})
+        child_instance = NestedDatamodel(name="Child Instance")
+        instance = self.env.datamodels["datamodel3"](child=child_instance)
+        res = self._to_response(instance)
+        self.assertEqual(res["child"]["name"], child_instance.name)
+        for datamodel_name in ("datamodel3", "nested_datamodel"):
+            schema = self.env.datamodels[datamodel_name].get_schema()
+            # schema 'unknown' is back to "raise"
+            self.assertEqual(schema.unknown, "raise")
diff --git a/base_rest_demo/datamodels/partner_info.py b/base_rest_demo/datamodels/partner_info.py
index f8f727851..991596298 100644
--- a/base_rest_demo/datamodels/partner_info.py
+++ b/base_rest_demo/datamodels/partner_info.py
@@ -18,4 +18,4 @@ class PartnerInfo(Datamodel):
     phone = fields.String(required=False, allow_none=True)
     state = NestedModel("state.info")
     country = NestedModel("country.info")
-    is_componay = fields.Boolean(required=False, allow_none=False)
+    is_company = fields.Boolean(required=False, allow_none=False)
diff --git a/datamodel/core.py b/datamodel/core.py
index 2665341f2..ee6c5a25e 100644
--- a/datamodel/core.py
+++ b/datamodel/core.py
@@ -5,6 +5,9 @@
 import functools
 import logging
 from collections import OrderedDict, defaultdict
+from contextlib import ExitStack
+
+from marshmallow import INCLUDE
 
 from odoo.api import Environment
 from odoo.tools import LastOrderedSet, OrderedSet
@@ -41,6 +44,14 @@ def _get_addon_name(full_name):
     return addon_name
 
 
+def _get_nested_schemas(schema):
+    res = [schema]
+    for field in schema.fields.values():
+        if getattr(field, "schema", None):
+            res += _get_nested_schemas(field.schema)
+    return res
+
+
 class DatamodelDatabases(dict):
     """ Holds a registry of datamodels for each database """
 
@@ -131,6 +142,13 @@ def __init__(self, name, bases, attrs):
 
         self._modules_datamodels[self._module].append(self)
 
+    def __call__(self, *args, **kwargs):
+        """Allow to set any field (including 'dump_only') at instantiation
+        This is not an issue thanks to cleanup during (de)serialization
+        """
+        kwargs["unknown"] = kwargs.get("unknown", INCLUDE)
+        return super().__call__(*args, **kwargs)
+
 
 class Datamodel(MarshmallowModel, metaclass=MetaDatamodel):
     """Main Datamodel Model
@@ -207,6 +225,18 @@ def get_schema(cls, **kwargs):
         """
         return cls.__get_schema_class__(**kwargs)
 
+    @classmethod
+    def validate(cls, data, context=None, many=None, partial=None, unknown=None):
+        schema = cls.__get_schema_class__(
+            context=context, partial=partial, unknown=unknown
+        )
+        all_schemas = _get_nested_schemas(schema)
+        with ExitStack() as stack:
+            # propagate 'unknown' to each nested schema during validate
+            for nested_schema in all_schemas:
+                stack.enter_context(cls.propagate_unknwown(nested_schema, unknown))
+            return schema.validate(data, many=many, partial=partial)
+
     @classmethod
     def _build_datamodel(cls, registry):
         """Instantiate a given Datamodel in the datamodels registry.
