diff --git a/Datatable/AbstractDatatable.php b/Datatable/AbstractDatatable.php
index 805d13cf..ef484a87 100755
--- a/Datatable/AbstractDatatable.php
+++ b/Datatable/AbstractDatatable.php
@@ -155,7 +155,8 @@ public function __construct(
         $translator,
         RouterInterface $router,
         EntityManagerInterface $em,
-        Environment $twig
+        Environment $twig,
+        iterable $columnTypes
     ) {
         $this->validateName();
 
@@ -177,7 +178,7 @@ public function __construct(
         $this->twig = $twig;
 
         $metadata = $em->getClassMetadata($this->getEntity());
-        $this->columnBuilder = new ColumnBuilder($metadata, $twig, $router, $this->getName(), $em);
+        $this->columnBuilder = new ColumnBuilder($metadata, $twig, $this->getName(), $em, $columnTypes);
 
         $this->ajax = new Ajax();
         $this->options = new Options();
diff --git a/Datatable/Column/AbstractColumn.php b/Datatable/Column/AbstractColumn.php
index e5c5f2cb..c073855e 100755
--- a/Datatable/Column/AbstractColumn.php
+++ b/Datatable/Column/AbstractColumn.php
@@ -240,14 +240,6 @@ abstract class AbstractColumn implements ColumnInterface
      */
     protected $twig;
 
-    /**
-     * The Router.
-     * Is set in the ColumnBuilder.
-     *
-     * @var RouterInterface
-     */
-    protected $router;
-
     /**
      * The position in the Columns array.
      * Is set in the ColumnBuilder.
diff --git a/Datatable/Column/ColumnBuilder.php b/Datatable/Column/ColumnBuilder.php
index ef439007..4e130e01 100755
--- a/Datatable/Column/ColumnBuilder.php
+++ b/Datatable/Column/ColumnBuilder.php
@@ -35,13 +35,6 @@ class ColumnBuilder
      */
     private $twig;
 
-    /**
-     * The router.
-     *
-     * @var RouterInterface
-     */
-    private $router;
-
     /**
      * The name of the associated Datatable.
      *
@@ -85,14 +78,18 @@ class ColumnBuilder
      */
     private $entityClassName;
 
+    /**
+     * @var iterable
+     */
+    private $columnTypes;
+
     /**
      * @param string $datatableName
      */
-    public function __construct(ClassMetadata $metadata, Environment $twig, RouterInterface $router, $datatableName, EntityManagerInterface $em)
+    public function __construct(ClassMetadata $metadata, Environment $twig, $datatableName, EntityManagerInterface $em, iterable $columnTypes)
     {
         $this->metadata = $metadata;
         $this->twig = $twig;
-        $this->router = $router;
         $this->datatableName = $datatableName;
         $this->em = $em;
 
@@ -100,6 +97,7 @@ public function __construct(ClassMetadata $metadata, Environment $twig, RouterIn
         $this->columnNames = [];
         $this->uniqueColumns = [];
         $this->entityClassName = $metadata->getName();
+        $this->columnTypes = $columnTypes;
     }
 
     //-------------------------------------------------
@@ -118,7 +116,22 @@ public function __construct(ClassMetadata $metadata, Environment $twig, RouterIn
      */
     public function add($dql, $class, array $options = [])
     {
-        $column = Factory::create($class, ColumnInterface::class);
+        if (\is_object($class)) {
+            $column = Factory::create($class, ColumnInterface::class);
+            @trigger_error(sprintf('Using an object as column type is deprecated and will be removed in 2.0. Use a class name (FQCN) instead.'), E_USER_DEPRECATED);
+        } else {
+            $columns = [];
+            foreach ($this->columnTypes as $column) {
+                $columns[\get_class($column)] = $column;
+            }
+
+            if (! \array_key_exists($class, $columns)) {
+                throw new \RuntimeException(sprintf('Column %s is not a service', $class));
+            }
+
+            $column = clone $columns[$class];
+        }
+
         $column->initOptions();
 
         $this->handleDqlProperties($dql, $options, $column);
@@ -269,7 +282,6 @@ private function setEnvironmentProperties(AbstractColumn $column)
         $column->setDatatableName($this->datatableName);
         $column->setEntityClassName($this->entityClassName);
         $column->setTwig($this->twig);
-        $column->setRouter($this->router);
 
         return $this;
     }
diff --git a/Datatable/Column/LinkColumn.php b/Datatable/Column/LinkColumn.php
index 51f0683e..b7df63d0 100644
--- a/Datatable/Column/LinkColumn.php
+++ b/Datatable/Column/LinkColumn.php
@@ -14,6 +14,7 @@
 use Sg\DatatablesBundle\Datatable\Filter\TextFilter;
 use Sg\DatatablesBundle\Datatable\Helper;
 use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Routing\RouterInterface;
 
 class LinkColumn extends AbstractColumn
 {
@@ -68,6 +69,16 @@ class LinkColumn extends AbstractColumn
      */
     protected $email;
 
+    /**
+     * @var RouterInterface
+     */
+    private $router;
+
+    public function __construct(RouterInterface $router)
+    {
+        $this->router = $router;
+    }
+
     //-------------------------------------------------
     // ColumnInterface
     //-------------------------------------------------
diff --git a/Datatable/Column/NumberColumn.php b/Datatable/Column/NumberColumn.php
index f363b4f3..676fd031 100644
--- a/Datatable/Column/NumberColumn.php
+++ b/Datatable/Column/NumberColumn.php
@@ -221,6 +221,8 @@ private function renderTemplate($data, $pk = null, $path = null)
             }
 
             $data = $this->formatter->formatCurrency($data, $this->currency);
+        } elseif ($data === null) {
+            $data = null;
         } else {
             // expected number (int or float), other values will be converted to a numeric value
             $data = $this->formatter->format($data);
diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
index a0fea356..b2d82740 100644
--- a/DependencyInjection/Configuration.php
+++ b/DependencyInjection/Configuration.php
@@ -20,7 +20,7 @@ class Configuration implements ConfigurationInterface
     /**
      * {@inheritdoc}
      */
-    public function getConfigTreeBuilder()
+    public function getConfigTreeBuilder(): TreeBuilder
     {
         $treeBuilder = new TreeBuilder('sg_datatables');
         if (method_exists($treeBuilder, 'getRootNode')) {
diff --git a/DependencyInjection/SgDatatablesExtension.php b/DependencyInjection/SgDatatablesExtension.php
index de9e785b..ad23cd40 100644
--- a/DependencyInjection/SgDatatablesExtension.php
+++ b/DependencyInjection/SgDatatablesExtension.php
@@ -11,6 +11,7 @@
 
 namespace Sg\DatatablesBundle\DependencyInjection;
 
+use Sg\DatatablesBundle\Datatable\Column\ColumnInterface;
 use Symfony\Component\Config\FileLocator;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
@@ -31,6 +32,9 @@ public function load(array $configs, ContainerBuilder $container)
         $loader->load('services.yml');
 
         $container->setParameter('sg_datatables.datatable.query', $config['datatable']['query']);
+        $container->registerForAutoconfiguration(ColumnInterface::class)
+            ->addTag('sg_datatables.column')
+        ;
     }
 
     /**
diff --git a/Resources/config/services.yml b/Resources/config/services.yml
index 594ca6ea..9e6230cc 100644
--- a/Resources/config/services.yml
+++ b/Resources/config/services.yml
@@ -1,12 +1,16 @@
 services:
-    sg_datatables.twig.extension:
-        class: Sg\DatatablesBundle\Twig\DatatableTwigExtension
-        public: false
-        tags:
-            - { name: twig.extension }
+    _defaults:
+        autoconfigure: true
+        autowire: true
 
-    sg_datatables.datatable.abstract:
-        class: Sg\DatatablesBundle\Datatable\AbstractDatatable
+    _instanceof:
+        Sg\DatatablesBundle\Datatable\Column\Column:
+            tags: ['sg_datatables.column']
+
+    Sg\DatatablesBundle\Datatable\Column\:
+        resource: '../../Datatable/Column/*'
+
+    Sg\DatatablesBundle\Datatable\AbstractDatatable:
         abstract: true
         arguments:
             - '@security.authorization_checker'
@@ -15,20 +19,29 @@ services:
             - '@router'
             - '@doctrine.orm.entity_manager'
             - '@twig'
+            - ! tagged sg_datatables.column
 
-    sg_datatables.response:
-        class: Sg\DatatablesBundle\Response\DatatableResponse
+    Sg\DatatablesBundle\Response\DatatableResponse:
         public: true
         arguments:
             - '@request_stack'
 
+    Sg\DatatablesBundle\Datatable\DatatableFactory:
+        public: true
+
+    Sg\DatatablesBundle\Twig\DatatableTwigExtension: ~
+
+    # aliases for backwards compatibility, will be removed in 2.0
+    sg_datatables.twig.extension:
+        alias: Sg\DatatablesBundle\Twig\DatatableTwigExtension
+
+    sg_datatables.datatable.abstract:
+        alias: Sg\DatatablesBundle\Datatable\AbstractDatatable
+
+    sg_datatables.response:
+        alias: Sg\DatatablesBundle\Response\DatatableResponse
+        public: true
+
     sg_datatables.factory:
-        class: Sg\DatatablesBundle\Datatable\DatatableFactory
+        alias: Sg\DatatablesBundle\Datatable\DatatableFactory
         public: true
-        arguments:
-            - '@security.authorization_checker'
-            - '@security.token_storage'
-            - '@translator'
-            - '@router'
-            - '@doctrine.orm.entity_manager'
-            - '@twig'
diff --git a/Resources/doc/cache.md b/Resources/doc/cache.md
index 5a669ee1..20abb7d9 100644
--- a/Resources/doc/cache.md
+++ b/Resources/doc/cache.md
@@ -12,9 +12,10 @@ Doctrine Query when creating response for DataTable.
 
 ``` php
 <?php
+use Sg\DatatablesBundle\Response\DatatableResponse;
 // ...
 if ($isAjax) {
-    $responseService = $this->get('sg_datatables.response');
+    $responseService = $this->get(DatatableResponse::class);
     $responseService->setDatatable($datatable);
 
     $datatableQueryBuilder = $responseService->getDatatableQueryBuilder();
diff --git a/Resources/doc/installation.md b/Resources/doc/installation.md
index 7cb98963..e0d17313 100644
--- a/Resources/doc/installation.md
+++ b/Resources/doc/installation.md
@@ -370,14 +370,19 @@ When declaring datatable "by hand" as extending `AbstractDatatable` class watch
 # app/config/services.yml
 
 services:
-    app.datatable.post:
-        class: AppBundle\Datatables\PostDatatable
-        parent: sg_datatables.datatable.abstract
+    _defaults:
+        autoconfigure: true
+        autowire: true
+    AppBundle\Datatables\PostDatatable:
+      bind:
+        $columnTypes: !tagged sg_datatables.column
 ```
 
 ### Step 3: The Controller actions
 
 ``` php
+use Sg\DatatablesBundle\Datatable\DatatableFactory;
+use Sg\DatatablesBundle\Response\DatatableResponse;
 /**
  * Lists all Post entities.
  *
@@ -398,11 +403,11 @@ public function indexAction(Request $request)
 
     // or use the DatatableFactory
     /** @var DatatableInterface $datatable */
-    $datatable = $this->get('sg_datatables.factory')->create(PostDatatable::class);
+    $datatable = $this->get(DatatableFactory::class)->create(PostDatatable::class);
     $datatable->buildDatatable();
 
     if ($isAjax) {
-        $responseService = $this->get('sg_datatables.response');
+        $responseService = $this->get(DatatableResponse::class);
         $responseService->setDatatable($datatable);
         $responseService->getDatatableQueryBuilder();
 
diff --git a/Resources/doc/query.md b/Resources/doc/query.md
index aba9af1e..41c64802 100644
--- a/Resources/doc/query.md
+++ b/Resources/doc/query.md
@@ -40,12 +40,14 @@ class Post
 Now you can view all posts created by `root`. The additional `where statement` now works like a filter.
 
 ``` php
+use Sg\DatatablesBundle\Response\DatatableResponse;
+
 public function indexAction(Request $request)
 {
     // ...
 
     if ($request->isXmlHttpRequest()) {
-        $responseService = $this->get('sg_datatables.response');
+        $responseService = $this->get(DatatableResponse::class);
         $responseService->setDatatable($datatable);
 
         $datatableQueryBuilder = $responseService->getDatatableQueryBuilder();
diff --git a/Response/DatatableQueryBuilder.php b/Response/DatatableQueryBuilder.php
index 8d8a340d..2445d5bb 100644
--- a/Response/DatatableQueryBuilder.php
+++ b/Response/DatatableQueryBuilder.php
@@ -186,6 +186,7 @@ class DatatableQueryBuilder
     //-------------------------------------------------
     // Ctor. && Init column arrays
     //-------------------------------------------------
+    private $columnNames;
 
     /**
      * @throws Exception
diff --git a/composer.json b/composer.json
index 3ce8d32a..8494161a 100755
--- a/composer.json
+++ b/composer.json
@@ -21,21 +21,21 @@
         "php": ">=7.2|>=8.0",
         "doctrine/orm": "^2.5",
         "friendsofsymfony/jsrouting-bundle": "^2.0|^3.0",
-        "symfony/config": "^4.4|^5.4|^6.0",
-        "symfony/dependency-injection": "^4.4|^5.4|^6.0",
-        "symfony/http-foundation": "^4.4|^5.4|^6.0",
-        "symfony/http-kernel": "^4.4|^5.4|^6.0",
-        "symfony/framework-bundle": "^4.4|^5.4|^6.0",
-        "symfony/options-resolver": "^4.4|^5.4|^6.0",
-        "symfony/property-access": "^4.4|^5.4|^6.0",
-        "symfony/routing": "^4.4|^5.4|^6.0",
-        "symfony/security-core": "^4.4|^5.4|^6.0",
-        "symfony/translation": "^4.4|^5.4|^6.0",
+        "symfony/config": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/dependency-injection": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/http-foundation": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/http-kernel": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/framework-bundle": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/options-resolver": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/property-access": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/routing": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/security-core": "^4.4|^5.4|^6.0|^7.0",
+        "symfony/translation": "^4.4|^5.4|^6.0|^7.0",
         "twig/twig": "^2.9|^3.0"
     },
     "require-dev": {
-        "phpunit/phpunit": "^8.5|^9.5",
-        "friendsofphp/php-cs-fixer": "^3.6"
+        "phpunit/phpunit": "^7.5|^8.5",
+        "friendsofphp/php-cs-fixer": "^2.15"
     },
     "autoload": {
         "psr-4": { "Sg\\DatatablesBundle\\": "" }