diff --git a/docsite/source/tolerance-to-unknown-arguments.html.md b/docsite/source/tolerance-to-unknown-arguments.html.md
index 23f303e..5a68b21 100644
--- a/docsite/source/tolerance-to-unknown-arguments.html.md
+++ b/docsite/source/tolerance-to-unknown-arguments.html.md
@@ -20,3 +20,47 @@ user.respond_to? :role # => false
 User.dry_initializer.attributes(user)
 # => {}
 ```
+
+Unknown arguments are stored in a pair of properties
+
+```ruby
+user.__dry_initializer_unknown_params__  # => ['Joe']
+user.__dry_initializer_unknown_options__ # => {role: 'admin'}
+```
+
+The names of the rest params and the rest options are configurable. 
+
+```ruby
+require 'dry-initializer'
+
+class User
+  extend Dry::Initializer
+
+  rest_params :args
+  rest_options :kwargs
+end
+
+user = User.new 'Joe', role: 'admin'
+user.args   # => ['Joe']
+user.kwargs # => {role: 'admin'}
+user.respond_to? :__dry_initializer_unknown_params__  # => false
+user.respond_to? :__dry_initializer_unknown_options__ # => false
+```
+
+Setting rest params or rest options to false results in strict argument checking.
+Unknown arguments will result in ArgumentErrors.
+
+```ruby
+require 'dry-initializer'
+
+class User
+  extend Dry::Initializer
+
+  rest_params false
+  rest_options false
+end
+
+user = User.new 'Joe'         # => raises ArgumentError
+user = User.new role: 'admin' # => raises ArgumentError
+
+```
\ No newline at end of file
diff --git a/lib/dry/initializer.rb b/lib/dry/initializer.rb
index b5f7905..b9a9400 100644
--- a/lib/dry/initializer.rb
+++ b/lib/dry/initializer.rb
@@ -47,6 +47,20 @@ def option(name, type = nil, **opts, &block)
       self
     end
 
+    # Sets rest params name or turns off rest params of [#dry_initializer]
+    # @param  [Symbol, nil] name
+    def rest_params(name)
+      dry_initializer.rest_params = name
+      self
+    end
+
+    # Sets rest options name or turns off rest options of [#dry_initializer]
+    # @param  [Symbol, nil] name
+    def rest_options(name)
+      dry_initializer.rest_options = name
+      self
+    end
+
     private
 
     def inherited(klass)
diff --git a/lib/dry/initializer/builders/attribute.rb b/lib/dry/initializer/builders/attribute.rb
index dab4f8b..76bd39d 100644
--- a/lib/dry/initializer/builders/attribute.rb
+++ b/lib/dry/initializer/builders/attribute.rb
@@ -21,10 +21,9 @@ def initialize(definition)
       @source     = definition.source
       @ivar       = definition.ivar
       @null       = definition.null ? 'Dry::Initializer::UNDEFINED' : 'nil'
-      @opts       = '__dry_initializer_options__'
       @congif     = '__dry_initializer_config__'
       @item       = '__dry_initializer_definition__'
-      @val        = @option ? '__dry_initializer_value__' : @source
+      @val        = @source
     end
     # rubocop: enable Metrics/MethodLength
 
@@ -32,28 +31,12 @@ def lines
       [
         '',
         definition_line,
-        reader_line,
         default_line,
         coercion_line,
         assignment_line
       ]
     end
 
-    def reader_line
-      return unless @option
-
-      @optional ? optional_reader : required_reader
-    end
-
-    def optional_reader
-      "#{@val} = #{@opts}.fetch(:'#{@source}', #{@null})"
-    end
-
-    def required_reader
-      "#{@val} = #{@opts}.fetch(:'#{@source}')" \
-      " { raise KeyError, \"\#{self.class}: #{@definition} is required\" }"
-    end
-
     def definition_line
       return unless @type || @default
 
diff --git a/lib/dry/initializer/builders/initializer.rb b/lib/dry/initializer/builders/initializer.rb
index a9aa9c2..354d75d 100644
--- a/lib/dry/initializer/builders/initializer.rb
+++ b/lib/dry/initializer/builders/initializer.rb
@@ -25,6 +25,7 @@ def lines
         define_line,
         params_lines,
         options_lines,
+        rest_lines,
         end_line
       ]
     end
@@ -50,6 +51,16 @@ def options_lines
         .map { |line| '  ' << line }
     end
 
+    def rest_lines
+      lines = []
+      lines << "@#{@config.rest_params} = #{@config.rest_params}" if @config.rest_params
+
+      if @config.rest_params && @definitions.any?(&:option)
+        lines << "@#{@config.rest_options} = #{@config.rest_options}"
+      end
+      lines.map { |line| "  " << line }
+    end
+
     def end_line
       'end'
     end
diff --git a/lib/dry/initializer/builders/signature.rb b/lib/dry/initializer/builders/signature.rb
index 480e4cd..d45ca69 100644
--- a/lib/dry/initializer/builders/signature.rb
+++ b/lib/dry/initializer/builders/signature.rb
@@ -6,7 +6,14 @@ def self.[](config)
     end
 
     def call
-      [*required_params, *optional_params, '*', options].compact.join(', ')
+      [
+        *required_params,
+        *optional_params,
+        rest_params,
+        *required_options,
+        *optional_options,
+        rest_options
+      ].compact.join(", ")
     end
 
     private
@@ -25,8 +32,20 @@ def optional_params
       @config.params.select(&:optional).map { |rec| "#{rec.source} = #{@null}" }
     end
 
-    def options
-      '**__dry_initializer_options__' if @options
+    def rest_params
+      "*#{@config.rest_params}" if @config.rest_params
+    end
+
+    def required_options
+      @config.options.reject(&:optional).map { |rec| "#{rec.source}:" }
+    end
+
+    def optional_options
+      @config.options.select(&:optional).map { |rec| "#{rec.source}: #{@null}" }
+    end
+
+    def rest_options
+      "**#{@config.rest_options}" if @options && @config.rest_options
     end
   end
 end
diff --git a/lib/dry/initializer/config.rb b/lib/dry/initializer/config.rb
index 49fa435..85a86b2 100644
--- a/lib/dry/initializer/config.rb
+++ b/lib/dry/initializer/config.rb
@@ -16,7 +16,7 @@ class Config
     # @return [Hash<Symbol, Dry::Initializer::Definition>]
     #   hash of attribute definitions with their source names
 
-    attr_reader :null, :extended_class, :parent, :definitions
+    attr_reader :null, :extended_class, :parent, :definitions, :rest_params, :rest_options
 
     # @!attribute [r] mixin
     # @return [Module] reference to the module to be included into class
@@ -71,6 +71,24 @@ def option(name, type = nil, **opts, &block)
       add_definition(true, name, type, block, **opts)
     end
 
+    # Sets rest parameter name or turns rest params off
+    # @param  [Symbol, nil] name
+    def rest_params=(name)
+      # remove the old attr_reader
+      mixin.class_eval(undef_method_code(@rest_params)) if @rest_params
+      @rest_params = name
+      finalize
+    end
+
+    # Sets rest options name or turns rest options off
+    # @param  [Symbol, nil] name
+    def rest_options=(name)
+      # remove the old attr_reader
+      mixin.class_eval(undef_method_code(@rest_options)) if @rest_options
+      @rest_options = name
+      finalize
+    end
+
     # The hash of public attributes for an instance of the [#extended_class]
     # @param  [Dry::Initializer::Instance] instance
     # @return [Hash<Symbol, Object>]
@@ -107,6 +125,7 @@ def finalize
       @definitions = final_definitions
       check_order_of_params
       mixin.class_eval(code)
+      mixin.class_eval(unknowns_code)
       children.each(&:finalize)
       self
     end
@@ -115,7 +134,6 @@ def finalize
     # @return [String]
     def inch
       line  =  Builders::Signature[self]
-      line  =  line.gsub('__dry_initializer_options__', 'options')
       lines =  ["@!method initialize(#{line})"]
       lines += ["Initializes an instance of #{extended_class}"]
       lines += definitions.values.map(&:inch)
@@ -131,6 +149,8 @@ def initialize(extended_class = nil, null: UNDEFINED)
       @parent         = sklass.dry_initializer if sklass.is_a? Dry::Initializer
       @null           = null || parent&.null
       @definitions    = {}
+      @rest_params = "__dry_initializer_unknown_params__"
+      @rest_options = "__dry_initializer_unknown_options__"
       finalize
     end
 
@@ -161,6 +181,17 @@ def final_definitions
       end
     end
 
+    def unknowns_code
+      lines = [undef_method_code(rest_params), undef_method_code(rest_options)]
+      lines << "attr_reader :#{rest_params}" if rest_params
+      lines << "attr_reader :#{rest_options}" if rest_options
+      lines.join("\n")
+    end
+
+    def undef_method_code(name)
+      "undef :#{name} if method_defined? :#{name}"
+    end
+
     def check_type(previous, current)
       return current unless previous
       return current if previous.option == current.option
diff --git a/lib/dry/initializer/dispatchers/prepare_target.rb b/lib/dry/initializer/dispatchers/prepare_target.rb
index 99da1d4..112c75a 100644
--- a/lib/dry/initializer/dispatchers/prepare_target.rb
+++ b/lib/dry/initializer/dispatchers/prepare_target.rb
@@ -9,7 +9,8 @@ module Dry::Initializer::Dispatchers::PrepareTarget
 
   # List of variable names reserved by the gem
   RESERVED = %i[
-    __dry_initializer_options__
+    __dry_initializer_unkown_params__
+    __dry_initializer_unkown_options__
     __dry_initializer_config__
     __dry_initializer_value__
     __dry_initializer_definition__
diff --git a/spec/attributes_spec.rb b/spec/attributes_spec.rb
index ee497db..3360b04 100644
--- a/spec/attributes_spec.rb
+++ b/spec/attributes_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 describe Dry::Initializer, "dry_initializer.attributes" do
   subject { instance.class.dry_initializer.attributes(instance) }
 
@@ -14,7 +16,15 @@ class Test::Foo
     let(:instance) { Test::Foo.new(:FOO) }
 
     it "collects coerced params with default values" do
-      expect(subject).to eq({ foo: "FOO", bar: 1 })
+      expect(subject).to eq({foo: "FOO", bar: 1})
+    end
+
+    context "with unknown params" do
+      let(:instance) { Test::Foo.new(:FOO, :BAR, :BAZ, :FUTZ) }
+
+      it "ignores extra params" do
+        expect(subject).to eq({foo: "FOO", bar: :BAR, baz: :BAZ})
+      end
     end
   end
 
@@ -32,7 +42,15 @@ class Test::Foo
     let(:instance) { Test::Foo.new(foo: :FOO, qux: :QUX) }
 
     it "collects coerced and renamed options with default values" do
-      expect(subject).to eq({ foo: :FOO, bar: 1, quxx: "QUX" })
+      expect(subject).to eq({foo: :FOO, bar: 1, quxx: "QUX"})
+    end
+
+    context "with extra unknown options" do
+      let(:instance) { Test::Foo.new(foo: :FOO, qux: :QUX, futz: :FUTZ) }
+
+      it "ignores extra options" do
+        expect(subject).to eq({foo: :FOO, bar: 1, quxx: "QUX"})
+      end
     end
   end
 end
diff --git a/spec/required_spec.rb b/spec/required_spec.rb
new file mode 100644
index 0000000..d03cb4f
--- /dev/null
+++ b/spec/required_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+describe "required param" do
+  before do
+    class Test::Foo
+      extend Dry::Initializer
+
+      param :foo
+      param :bar, optional: true
+    end
+  end
+
+  it "raise ArgumentError" do
+    expect { Test::Foo.new }.to raise_exception(ArgumentError)
+  end
+end
+
+describe "required option" do
+  before do
+    class Test::Foo
+      extend Dry::Initializer
+
+      option :foo
+      option :bar, optional: true
+    end
+  end
+
+  it "raise ArgumentError" do
+    expect { Test::Foo.new }.to raise_exception(ArgumentError)
+  end
+end
diff --git a/spec/several_assignments_spec.rb b/spec/several_assignments_spec.rb
index 6132fc1..158e400 100644
--- a/spec/several_assignments_spec.rb
+++ b/spec/several_assignments_spec.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
 describe "attribute with several assignments" do
   before do
     class Test::Foo
       extend Dry::Initializer
 
-      option :bar, proc(&:to_s),    optional: true
-      option :"some foo", as: :bar, optional: true
+      option :bar, proc(&:to_s), optional: true
+      option "some_foo", as: :bar, optional: true
     end
   end
 
@@ -13,7 +15,7 @@ class Test::Foo
 
     it "is left undefined" do
       expect(subject.bar).to be_nil
-      expect(subject.instance_variable_get :@bar)
+      expect(subject.instance_variable_get(:@bar))
         .to eq Dry::Initializer::UNDEFINED
     end
   end
@@ -27,7 +29,7 @@ class Test::Foo
   end
 
   context "when renamed" do
-    subject { Test::Foo.new "some foo": :BAZ }
+    subject { Test::Foo.new "some_foo": :BAZ }
 
     it "renames the attribute" do
       expect(subject.bar).to eq :BAZ
diff --git a/spec/unknown_spec.rb b/spec/unknown_spec.rb
new file mode 100644
index 0000000..ccc9525
--- /dev/null
+++ b/spec/unknown_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+describe "unknow param" do
+  before do
+    class Test::Foo
+      extend Dry::Initializer
+
+      param :foo
+      param :bar, optional: true
+    end
+  end
+
+  it "suports unknown params" do
+    subject = Test::Foo.new(1, 2, 3, 4)
+
+    expect(subject.__dry_initializer_unknown_params__).to eq([3, 4])
+  end
+
+  it "suports unknown params with last as hash" do
+    subject = Test::Foo.new(1, 2, 3, {fizz: 4})
+
+    expect(subject.__dry_initializer_unknown_params__).to eq([3, {fizz: 4}])
+  end
+
+  context "with custom rest params" do
+    before do
+      class Test::Bar
+        extend Dry::Initializer
+
+        param :foo
+        param :bar, optional: true
+        rest_params :qux
+      end
+    end
+
+    it "supports unknown options" do
+      subject = Test::Bar.new(1, 2, 3, 4)
+
+      expect(subject.qux).to eq([3, 4])
+    end
+  end
+
+  context "without rest params" do
+    before do
+      class Test::Bar
+        extend Dry::Initializer
+
+        param :foo
+        param :bar, optional: true
+        rest_params false
+      end
+    end
+
+    it "raise an ArgumentError" do
+      expect { Test::Bar.new(1, 2, 3, 4) }.to raise_exception ArgumentError
+    end
+  end
+end
+
+describe "unknown option" do
+  before do
+    class Test::Foo
+      extend Dry::Initializer
+
+      option :foo
+      option :bar, optional: true
+    end
+  end
+
+  it "supports unknown options" do
+    subject = Test::Foo.new(foo: 1, bar: 2, fizz: 3, buzz: 4)
+
+    expect(subject.__dry_initializer_unknown_options__).to eq(fizz: 3, buzz: 4)
+  end
+
+  context "with custom rest options" do
+    before do
+      class Test::Bar
+        extend Dry::Initializer
+
+        option :foo
+        option :bar, optional: true
+        rest_options :kwargs
+      end
+    end
+
+    it "supports unknown options" do
+      subject = Test::Bar.new(foo: 1, bar: 2, fizz: 3, buzz: 4)
+
+      expect(subject.kwargs).to eq(fizz: 3, buzz: 4)
+    end
+  end
+
+  context "with out rest options" do
+    before do
+      class Test::Bar
+        extend Dry::Initializer
+
+        option :foo
+        option :bar, optional: true
+        rest_options false
+      end
+    end
+
+    it "raise an ArgumentError" do
+      expect { Test::Bar.new(foo: 1, bar: 2, fizz: 3, buzz: 4) }.to raise_exception ArgumentError
+    end
+  end
+end