diff --git a/IPython/extensions/autoreload.py b/IPython/extensions/autoreload.py
index ada680f..1b86e0c 100644
--- a/IPython/extensions/autoreload.py
+++ b/IPython/extensions/autoreload.py
@@ -48,6 +48,12 @@ The following magic commands are provided:
     Reload all modules (except those excluded by ``%aimport``) every
     time before executing the Python code typed.
 
+``%autoreload 3``
+
+    Reload all modules AND autoload newly added objects
+        (except those excluded by ``%aimport``)
+    every time before executing the Python code typed.
+
 ``%aimport``
 
     List modules which are to be automatically imported or not to be imported.
@@ -131,7 +137,10 @@ class ModuleReloader(object):
     check_all = True
     """Autoreload all modules, not just those listed in 'modules'"""
 
-    def __init__(self):
+    autoload_obj = False
+    """Autoreload all modules AND autoload all new objects"""
+
+    def __init__(self, shell=None):
         # Modules that failed to reload: {module: mtime-on-failed-reload, ...}
         self.failed = {}
         # Modules specially marked as autoreloadable.
@@ -142,6 +151,7 @@ class ModuleReloader(object):
         self.old_objects = {}
         # Module modification timestamps
         self.modules_mtimes = {}
+        self.shell = shell
 
         # Cache module modification times
         self.check(check_all=True, do_reload=False)
@@ -242,7 +252,10 @@ class ModuleReloader(object):
             # If we've reached this point, we should try to reload the module
             if do_reload:
                 try:
-                    superreload(m, reload, self.old_objects)
+                    if self.autoload_obj:
+                        superreload(m, reload, self.old_objects, self.shell)
+                    else:
+                        superreload(m, reload, self.old_objects)
                     if py_filename in self.failed:
                         del self.failed[py_filename]
                 except:
@@ -356,7 +369,25 @@ class StrongRef(object):
         return self.obj
 
 
-def superreload(module, reload=reload, old_objects=None):
+def append_obj(module, d, name, obj, autoload=False):
+    not_in_mod = not hasattr(obj, '__module__') or obj.__module__ != module.__name__
+    if autoload:
+        # check needed for module global built-ins (int, str, dict,..)
+        if name.startswith('__') and not_in_mod:
+            return False
+    else:
+        if not_in_mod:
+            return False
+
+    key = (module.__name__, name)
+    try:
+        d.setdefault(key, []).append(weakref.ref(obj))
+    except TypeError:
+        pass
+    return True
+
+
+def superreload(module, reload=reload, old_objects=None, shell=None):
     """Enhanced version of the builtin reload function.
 
     superreload remembers objects previously in the module, and
@@ -371,7 +402,7 @@ def superreload(module, reload=reload, old_objects=None):
 
     # collect old objects in the module
     for name, obj in list(module.__dict__.items()):
-        if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
+        if not append_obj(module, old_objects, name, obj):
             continue
         key = (module.__name__, name)
         try:
@@ -400,7 +431,15 @@ def superreload(module, reload=reload, old_objects=None):
     # iterate over all objects and update functions & classes
     for name, new_obj in list(module.__dict__.items()):
         key = (module.__name__, name)
-        if key not in old_objects: continue
+        if key not in old_objects:
+            # here 'shell' acts both as a flag and as an output var
+            if (
+                shell is None or
+                name == 'Enum' or
+                not append_obj(module, old_objects, name, new_obj, True)
+            ):
+                continue
+            shell.user_ns[name] = new_obj
 
         new_refs = []
         for old_ref in old_objects[key]:
@@ -426,8 +465,9 @@ from IPython.core.magic import Magics, magics_class, line_magic
 class AutoreloadMagics(Magics):
     def __init__(self, *a, **kw):
         super(AutoreloadMagics, self).__init__(*a, **kw)
-        self._reloader = ModuleReloader()
+        self._reloader = ModuleReloader(self.shell)
         self._reloader.check_all = False
+        self._reloader.autoload_obj = False
         self.loaded_modules = set(sys.modules)
 
     @line_magic
@@ -485,6 +525,11 @@ class AutoreloadMagics(Magics):
         elif parameter_s == '2':
             self._reloader.check_all = True
             self._reloader.enabled = True
+            self._reloader.enabled = True
+        elif parameter_s == '3':
+            self._reloader.check_all = True
+            self._reloader.enabled = True
+            self._reloader.autoload_obj = True
 
     @line_magic
     def aimport(self, parameter_s='', stream=None):
diff --git a/IPython/extensions/tests/test_autoreload.py b/IPython/extensions/tests/test_autoreload.py
index e81bf22..141307c 100644
--- a/IPython/extensions/tests/test_autoreload.py
+++ b/IPython/extensions/tests/test_autoreload.py
@@ -252,6 +252,89 @@ class TestAutoreload(Fixture):
             with nt.assert_raises(AttributeError):
                 self.shell.run_code("{object_name}.toto".format(object_name=object_name))
 
+    def test_autoload_newly_added_objects(self):
+        self.shell.magic_autoreload("3")
+        mod_code = """
+        def func1(): pass
+        """
+        mod_name, mod_fn = self.new_module(textwrap.dedent(mod_code))
+        self.shell.run_code(f"from {mod_name} import *")
+        self.shell.run_code("func1()")
+        with nt.assert_raises(NameError):
+            self.shell.run_code('func2()')
+        with nt.assert_raises(NameError):
+            self.shell.run_code('t = Test()')
+        with nt.assert_raises(NameError):
+            self.shell.run_code('number')
+
+        # ----------- TEST NEW OBJ LOADED --------------------------
+
+        new_code = """
+        def func1(): pass
+        def func2(): pass
+        class Test: pass
+        number = 0
+        from enum import Enum
+        class TestEnum(Enum):
+            A = 'a'
+        """
+        self.write_file(mod_fn, textwrap.dedent(new_code))
+
+        # test function now exists in shell's namespace namespace
+        self.shell.run_code("func2()")
+        # test function now exists in module's dict
+        self.shell.run_code(f"import sys; sys.modules['{mod_name}'].func2()")
+        # test class now exists
+        self.shell.run_code("t = Test()")
+        # test global built-in var now exists
+        self.shell.run_code('number')
+        # test the enumerations gets loaded succesfully
+        self.shell.run_code("TestEnum.A")
+
+        # ----------- TEST NEW OBJ CAN BE CHANGED --------------------
+
+        new_code = """
+        def func1(): return 'changed'
+        def func2(): return 'changed'
+        class Test:
+            def new_func(self):
+                return 'changed'
+        number = 1
+        from enum import Enum
+        class TestEnum(Enum):
+            A = 'a'
+            B = 'added'
+        """
+        self.write_file(mod_fn, textwrap.dedent(new_code))
+        self.shell.run_code("assert func1() == 'changed'")
+        self.shell.run_code("assert func2() == 'changed'")
+        self.shell.run_code("t = Test(); assert t.new_func() == 'changed'")
+        self.shell.run_code("assert number == 1")
+        self.shell.run_code("assert TestEnum.B.value == 'added'")
+
+        # ----------- TEST IMPORT FROM MODULE --------------------------
+
+        new_mod_code = '''
+        from enum import Enum
+        class Ext(Enum):
+            A = 'ext'
+        def ext_func():
+            return 'ext'
+        class ExtTest:
+            def meth(self):
+                return 'ext'
+        ext_int = 2
+        '''
+        new_mod_name, new_mod_fn = self.new_module(textwrap.dedent(new_mod_code))
+        current_mod_code = f'''
+        from {new_mod_name} import *
+        '''
+        self.write_file(mod_fn, textwrap.dedent(current_mod_code))
+        self.shell.run_code("assert Ext.A.value == 'ext'")
+        self.shell.run_code("assert ext_func() == 'ext'")
+        self.shell.run_code("t = ExtTest(); assert t.meth() == 'ext'")
+        self.shell.run_code("assert ext_int == 2")
+
     def _check_smoketest(self, use_aimport=True):
         """
         Functional test for the automatic reloader using either
diff --git a/docs/source/whatsnew/pr/autoreload-option-3-feature.rst b/docs/source/whatsnew/pr/autoreload-option-3-feature.rst
new file mode 100644
index 0000000..1adc444
--- /dev/null
+++ b/docs/source/whatsnew/pr/autoreload-option-3-feature.rst
@@ -0,0 +1,14 @@
+Autoreload 3 feature
+====================
+
+Example: When an IPython session is ran with the 'autoreload' extension loaded,
+you will now have the option '3' to select which means the following:
+
+    1. replicate all functionality from option 2
+    2. autoload all new funcs/classes/enums/globals from the module when they're added
+    3. autoload all newly imported funcs/classes/enums/globals from external modules
+
+Try ``%autoreload 3`` in an IPython session after running ``%load_ext autoreload``
+
+For more information please see unit test - 
+    extensions/tests/test_autoreload.py : 'test_autoload_newly_added_objects'