diff --git a/include/class_objects.inc b/include/class_objects.inc
index cc4e807de63a9c1c8310c26fa45585b4c6c8a1ea..9d4cb560d84f51f8a6d1ac89ae188e57b9da4f2b 100644
--- a/include/class_objects.inc
+++ b/include/class_objects.inc
@@ -42,7 +42,7 @@ class objects
    *
    * \return The list of objects as an associative array (keys are dns)
    */
-  static function ls ($types, $attrs = NULL, $ou = NULL, $filter = '', $checkAcl = FALSE, $scope = 'subtree')
+  static function ls ($types, $attrs = NULL, $ou = NULL, $filter = '', $checkAcl = FALSE, $scope = 'subtree', $templateSearch = FALSE)
   {
     global $ui, $config;
 
@@ -105,7 +105,7 @@ class objects
     }
 
     try {
-      $ldap = static::search($types, $search_attrs, $ou, $filter, $checkAcl, $scope, FALSE, $partialFilterAcls);
+      $ldap = static::search($types, $search_attrs, $ou, $filter, $checkAcl, $scope, $templateSearch, $partialFilterAcls);
     } catch (NonExistingBranchException $e) {
       return array();
     }
@@ -166,10 +166,10 @@ class objects
    *
    * \return The number of objects of type $type in $ou
    */
-  static function count ($types, $ou = NULL, $filter = '', $checkAcl = FALSE)
+  static function count ($types, $ou = NULL, $filter = '', $checkAcl = FALSE, $templateSearch = FALSE)
   {
     try {
-      $ldap = static::search($types, array('dn'), $ou, $filter, $checkAcl, 'subtree', FALSE, $partialFilterAcls);
+      $ldap = static::search($types, array('dn'), $ou, $filter, $checkAcl, 'subtree', $templateSearch, $partialFilterAcls);
       if (!empty($partialFilterAcls)) {
         throw new FusionDirectoryException('Not enough rights to use "'.$partialFilterAcls[0][1].'" in filter');
       }
diff --git a/include/class_templateHandling.inc b/include/class_templateHandling.inc
index 54c5f8ec7528cb2b9591fddcb289621f5d744421..d149e0e788ac6d3896713ab33c38f085a094fcde 100644
--- a/include/class_templateHandling.inc
+++ b/include/class_templateHandling.inc
@@ -45,17 +45,19 @@ class templateHandling
   /*! \brief Translate template attrs into $attrs as if taken from LDAP */
   public static function fieldsFromLDAP (array $template_attrs)
   {
-    unset($template_attrs['fdTemplateField']['count']);
-    sort($template_attrs['fdTemplateField']);
     $attrs = array();
-    foreach ($template_attrs['fdTemplateField'] as $field) {
-      preg_match('/^([^:]+):(.*)$/s', $field, $m);
-      if (isset($attrs[$m[1]])) {
-        $attrs[$m[1]][] = $m[2];
-        $attrs[$m[1]]['count']++;
-      } else {
-        $attrs[$m[1]]           = array($m[2]);
-        $attrs[$m[1]]['count']  = 1;
+    if (isset($template_attrs['fdTemplateField'])) {
+      unset($template_attrs['fdTemplateField']['count']);
+      sort($template_attrs['fdTemplateField']);
+      foreach ($template_attrs['fdTemplateField'] as $field) {
+        preg_match('/^([^:]+):(.*)$/s', $field, $m);
+        if (isset($attrs[$m[1]])) {
+          $attrs[$m[1]][] = $m[2];
+          $attrs[$m[1]]['count']++;
+        } else {
+          $attrs[$m[1]]           = array($m[2]);
+          $attrs[$m[1]]['count']  = 1;
+        }
       }
     }
     return $attrs;
diff --git a/include/management/class_ListingEntry.inc b/include/management/class_ListingEntry.inc
new file mode 100644
index 0000000000000000000000000000000000000000..694fc3c26c34a3d466201b1acb00d1d1368226d6
--- /dev/null
+++ b/include/management/class_ListingEntry.inc
@@ -0,0 +1,91 @@
+<?php
+/*
+  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
+  Copyright (C) 2017-2018  FusionDirectory
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+class ListingEntry implements ArrayAccess
+{
+  public $dn;
+  public $row;
+  public $type;
+  private $attrs;
+  protected $listing;
+
+  public function __construct(managementListing $listing, $type, $dn, array $attrs, $row = NULL) {
+    $this->listing  = $listing;
+    $this->type     = $type;
+    $this->dn       = $dn;
+    $this->attrs    = $attrs;
+    $this->row      = $row;
+  }
+
+  public function offsetSet($offset, $value) {
+    if (is_null($offset)) {
+      $this->container[] = $value;
+    } else {
+      $this->attrs[$offset] = $value;
+    }
+  }
+
+  public function offsetExists($offset) {
+    return isset($this->attrs[$offset]);
+  }
+
+  public function offsetUnset($offset) {
+    unset($this->attrs[$offset]);
+  }
+
+  public function offsetGet($offset) {
+    return (isset($this->attrs[$offset]) ? $this->attrs[$offset] : NULL);
+  }
+
+  public function getPid()
+  {
+    return $this->listing->pid;
+  }
+
+  public function isTemplate()
+  {
+    return preg_match('/^template_/', $this->type);
+  }
+
+  public function getTemplatedType()
+  {
+    return preg_replace('/^template_/', '', $this->type);
+  }
+
+  public function getTemplatedFields()
+  {
+    return templateHandling::fieldsFromLDAP($this->attrs);
+  }
+
+  public function checkAcl($acls)
+  {
+    global $ui;
+
+    $infos  = objects::infos($this->getTemplatedType());
+    $rights = $ui->get_permissions($this->dn, $infos['aclCategory'].'/'.($this->isTemplate() ? 'template' : $infos['mainTab']));
+    foreach (str_split($acls) as $acl) {
+      if (strpos($rights, $acl) === FALSE) {
+        return FALSE;
+      }
+    }
+
+    return TRUE;
+  }
+}
diff --git a/include/management/class_management.inc b/include/management/class_management.inc
index 3991119fc3131db6c700fe41e4a44853cf5b4bbd..6e09ef3cba069b850c83abe1ec6691575f0659fe 100644
--- a/include/management/class_management.inc
+++ b/include/management/class_management.inc
@@ -53,6 +53,8 @@ class management
 
   public $neededAttrs = array();
 
+  public static $skipTemplates = TRUE;
+
   // Whether to display a header or not.
   protected $skipHeader = FALSE;
 
@@ -444,6 +446,36 @@ class management
     return $str;
   }
 
+  function handleTemplateApply ($cancel = FALSE)
+  {
+    if (static::$skipTemplates) {
+      return;
+    }
+    if ($cancel) {
+      $msgs = array();
+    } else {
+      $msgs = $this->tabObject->save();
+    }
+    if (count($msgs)) {
+      msg_dialog::displayChecks($msgs);
+      return;
+    } else {
+      if (!$cancel) {
+        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, 'Template applied!');
+      }
+      del_lock($this->dn);
+      if (empty($this->dns)) {
+        $this->closeDialogs();
+      } else {
+        $this->last_tabObject = $this->tabObject;
+        $this->tabObject      = NULL;
+        $this->dn             = array_shift($this->dns);
+        $this->dialogObject->setNextTarget($this->dn);
+        $this->dialogObject->save_object();
+      }
+    }
+  }
+
   /* Action handlers */
 
   /*!
@@ -485,14 +517,11 @@ class management
 
     $target = array_pop($action['targets']);
 
-    $type = $this->listing->getType($target);
-    if ($type === NULL) {
-      trigger_error('Could not find type for '.$target.', open canceled');
+    $entry = $this->listing->getEntry($target);
+    if ($entry === NULL) {
+      trigger_error('Could not find '.$target.', open canceled');
       return;
     }
-    //~ if (preg_match('/^template_/', $type) && !static::$skipTemplates) {
-      //~ $type = preg_replace('/^template_/', '', $type);
-    //~ }
 
     // Get the dn of the object and create lock
     $this->dn = $target;
@@ -503,7 +532,7 @@ class management
     add_lock ($this->dn, $ui->dn);
 
     // Open object
-    $this->openTabObject(objects::open($this->dn, $type), $this->dn);
+    $this->openTabObject(objects::open($this->dn, $entry->getTemplatedType()), $this->dn);
     @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, 'Edit entry initiated');
     if (isset($action['subaction'])) {
       if ($this->handleSubAction($action) == FALSE) {
@@ -518,10 +547,10 @@ class management
    */
   function cancelEdit()
   {
-    //~ if (($this->tabObject instanceOf simpleTabs) && ($this->dialogObject instanceOf templateDialog)) {
-      //~ $this->handleTemplateApply(TRUE);
-      //~ return;
-    //~ }
+    if (($this->tabObject instanceOf simpleTabs) && ($this->dialogObject instanceOf templateDialog)) {
+      $this->handleTemplateApply(TRUE);
+      return;
+    }
     $this->remove_lock();
     $this->closeDialogs();
   }
@@ -533,11 +562,11 @@ class management
    */
   function saveChanges()
   {
-    //~ if (($this->tabObject instanceOf simpleTabs) && ($this->dialogObject instanceOf templateDialog)) {
-      //~ $this->tabObject->save_object();
-      //~ $this->handleTemplateApply();
-      //~ return;
-    //~ }
+    if (($this->tabObject instanceOf simpleTabs) && ($this->dialogObject instanceOf templateDialog)) {
+      $this->tabObject->save_object();
+      $this->handleTemplateApply();
+      return;
+    }
     if ($this->tabObject instanceOf simpleTabs) {
       $this->tabObject->save_object();
       $msgs = $this->tabObject->save();
@@ -594,14 +623,9 @@ class management
 
     // Check permissons for each target
     foreach ($action['targets'] as $dn) {
-      $type = $this->listing->getType($dn);
-      //~ if (preg_match('/^template_/', $type) && !static::$skipTemplates) {
-        //~ $type = preg_replace('/^template_/', '', $type);
-      //~ }
+      $entry = $this->listing->getEntry($dn);
       try {
-        $info = objects::infos($type);
-        $acl  = $ui->get_permissions($dn, $info['aclCategory'].'/'.$info['mainTab']);
-        if (preg_match('/d/', $acl)) {
+        if ($entry->checkAcl('d')) {
           $this->dns[] = $dn;
         } else {
           $disallowed[] = $dn;
@@ -625,19 +649,15 @@ class management
       $objects = array();
       foreach ($this->dns as $dn) {
         $entry  = $this->listing->getEntry($dn);
-        $type   = $entry->type;
-        if (preg_match('/^template_/', $type) && !static::$skipTemplates) {
-          $type = preg_replace('/^template_/', '', $type);
-          $info = objects::infos($type);
-          $info['nameAttr'] = 'cn';
-        } else {
-          $info = objects::infos($type);
+        $infos  = objects::infos($entry->getTemplatedType());
+        if ($entry->isTemplate()) {
+          $infos['nameAttr'] = 'cn';
         }
         $objects[] = array(
-          'name'  => $entry[$info['nameAttr']],
+          'name'  => $entry[$infos['nameAttr']],
           'dn'    => $dn,
-          'icon'  => $info['icon'],
-          'type'  => $info['name']
+          'icon'  => $infos['icon'],
+          'type'  => $infos['name']
         );
       }
       add_lock ($this->dns, $ui->dn);
@@ -659,20 +679,14 @@ class management
     @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dns, 'Entry deletion confirmed');
 
     foreach ($this->dns as $dn) {
-      $type = $this->listing->getType($dn);
-      if (empty($type)) {
+      $entry = $this->listing->getEntry($dn);
+      if (empty($entry)) {
         continue;
       }
-      //~ if (preg_match('/^template_/', $type) && !static::$skipTemplates) {
-        //~ $type = preg_replace('/^template_/', '', $type);
-      //~ }
-      $infos = objects::infos($type);
-      // Check permissions, are we allowed to remove this object?
-      $acl = $ui->get_permissions($dn, $infos['aclCategory'].'/'.$infos['mainTab']);
-      if (preg_match('/d/', $acl)) {
+      if ($entry->checkAcl('d')) {
         // Delete the object
         $this->dn = $dn;
-        $this->openTabObject(objects::open($this->dn, $type), $this->dn);
+        $this->openTabObject(objects::open($this->dn, $entry->getTemplatedType()), $this->dn);
         $this->tabObject->delete();
 
         // Remove the lock for the current object.
diff --git a/include/management/class_managementAction.inc b/include/management/class_managementAction.inc
index b3ef2870af04474f8632451311919346480af7fb..e2c2f712f8bd884ecf455850ef2e7a072291932a 100644
--- a/include/management/class_managementAction.inc
+++ b/include/management/class_managementAction.inc
@@ -136,7 +136,7 @@ class Action
     }
 
     // Skip the entry completely if there's no permission to execute it
-    if (!$this->hasPermission($entry->dn, $entry->type)) {
+    if (!$this->hasPermission($entry->dn, $entry->getTemplatedType(), $entry->isTemplate())) {
       return '<img src="images/empty.png" alt=" " class="center optional"/>';
     }
 
@@ -148,7 +148,7 @@ class Action
             ' title="'.$this->label.'" alt="'.$this->label.'" name="listing_'.$this->name.'_'.$entry->row.'"/>';
   }
 
-  function hasPermission($dn, $type)
+  function hasPermission($dn, $type, $template)
   {
     global $ui;
 
@@ -160,7 +160,11 @@ class Action
         $checkAcl = $ui->get_permissions($dn, $module, $m[1]);
         $acl      = $m[2];
       } else {
-        $module   = $infos['aclCategory'].'/'.$infos['mainTab'];
+        if ($template) {
+          $module = $infos['aclCategory'].'/template';
+        } else {
+          $module = $infos['aclCategory'].'/'.$infos['mainTab'];
+        }
         $checkAcl = $ui->get_permissions($dn, $module, '0');
       }
 
diff --git a/include/management/class_managementColumn.inc b/include/management/class_managementColumn.inc
index e0442a44b47b46771f91e5311fbb40932a6cb5e4..3f527a6a7762d94128dc3db82e4fc8b5b39890fd 100644
--- a/include/management/class_managementColumn.inc
+++ b/include/management/class_managementColumn.inc
@@ -27,6 +27,8 @@ class StringColumn
   protected $label;
   protected $type = 'string';
 
+  protected $templateAttribute = NULL;
+
   /* management class instance */
   protected $parent = NULL;
 
@@ -36,6 +38,11 @@ class StringColumn
     $this->label      = $label;
   }
 
+  function setTemplateAttribute($attribute)
+  {
+    $this->templateAttribute = $attribute;
+  }
+
   function setParent(managementListing $parent)
   {
     $this->parent = $parent;
@@ -79,8 +86,12 @@ class StringColumn
 
   function renderCell(ListingEntry $entry)
   {
-    if (isset($this->attribute) && isset($entry[$this->attribute])) {
-      return htmlentities($entry[$this->attribute], ENT_COMPAT, 'UTF-8');
+    $attribute = $this->attribute;
+    if (isset($this->templateAttribute) && $entry->isTemplate()) {
+      $attribute = $this->templateAttribute;
+    }
+    if (isset($attribute) && isset($entry[$attribute])) {
+      return htmlentities($entry[$attribute], ENT_COMPAT, 'UTF-8');
     } else {
       return '&nbsp;';
     }
@@ -155,8 +166,12 @@ class LinkColumn extends StringColumn
 {
   function renderCell(ListingEntry $entry)
   {
-    if (isset($entry[$this->attribute])) {
-      return '<a href="?plug='.$_GET['plug'].'&amp;PID='.$entry->getPid().'&amp;act=listing_edit_'.$entry->row.'" title="'.$entry->dn.'">'.htmlentities($entry[$this->attribute], ENT_COMPAT, 'UTF-8').'</a>';
+    $attribute = $this->attribute;
+    if (isset($this->templateAttribute) && $entry->isTemplate()) {
+      $attribute = $this->templateAttribute;
+    }
+    if (isset($entry[$attribute])) {
+      return '<a href="?plug='.$_GET['plug'].'&amp;PID='.$entry->getPid().'&amp;act=listing_edit_'.$entry->row.'" title="'.$entry->dn.'">'.htmlentities($entry[$attribute], ENT_COMPAT, 'UTF-8').'</a>';
     } else {
       return '&nbsp;';
     }
@@ -172,7 +187,10 @@ class ObjectTypeColumn extends StringColumn
 
   function renderCell(ListingEntry $entry)
   {
-    if ($entry->type) {
+    if ($entry->isTemplate()) {
+      $infos = objects::infos($entry->getTemplatedType());
+      return '<img class="center" title="'.$entry->dn.'" src="'.htmlentities('geticon.php?context=devices&icon=template&size=16', ENT_COMPAT, 'UTF-8').'" alt="'.sprintf(_('%s template'), $infos['name']).'"/>';
+    } elseif ($entry->type) {
       $infos = objects::infos($entry->type);
       return '<img class="center" title="'.$entry->dn.'" src="'.htmlentities($infos['icon'], ENT_COMPAT, 'UTF-8').'" alt="'.$infos['name'].'"/>';
     } else {
@@ -215,7 +233,7 @@ class PropertiesColumn extends StringColumn
   {
     global $config;
 
-    $infos = objects::infos($entry->type);
+    $infos = objects::infos($entry->getTemplatedType());
 
     static $tabs = array();
 
@@ -239,11 +257,13 @@ class PropertiesColumn extends StringColumn
                'alt="'.$pInfos['plShortName'].'" title="'.$pInfos['plShortName'].'" '.
                'name="listing_edit_tab_'.$infos['mainTab'].'_'.$entry->row.'"/>';
     if (!empty($entry)) {
-      //~ if (in_array_ics ('fdTemplate', $attrs['objectClass'])) {
-        //~ $attrs = templateHandling::fieldsFromLDAP($attrs);
-      //~ }
+      if ($entry->isTemplate()) {
+        $attrs = $entry->getTemplatedFields();
+      } else {
+        $attrs = $entry;
+      }
       foreach ($tabs[$entry->type] as $class => $tab) {
-        if ($tab->is_this_account($entry)) {
+        if ($tab->is_this_account($attrs)) {
           $pInfos = pluglist::pluginInfos($class);
           if (isset($pInfos['plSmallIcon'])) {
             $result .= '<input class="center" type="image" src="'.htmlentities($pInfos['plSmallIcon'], ENT_COMPAT, 'UTF-8').'" '.
diff --git a/include/management/class_managementListing.inc b/include/management/class_managementListing.inc
index ad90979be3b08b13f8ff536f0ffe07882d4dbadf..2c3fb8b48495828d93a2abc324918de9d80a1432 100644
--- a/include/management/class_managementListing.inc
+++ b/include/management/class_managementListing.inc
@@ -114,48 +114,6 @@ class entrySortIterator implements Iterator {
   }
 }
 
-class ListingEntry implements ArrayAccess
-{
-  public $dn;
-  public $row;
-  public $type;
-  private $attrs;
-  protected $listing;
-
-  public function __construct(managementListing $listing, $type, $dn, array $attrs, $row = NULL) {
-    $this->listing  = $listing;
-    $this->type     = $type;
-    $this->dn       = $dn;
-    $this->attrs    = $attrs;
-    $this->row      = $row;
-  }
-
-  public function offsetSet($offset, $value) {
-    if (is_null($offset)) {
-      $this->container[] = $value;
-    } else {
-      $this->attrs[$offset] = $value;
-    }
-  }
-
-  public function offsetExists($offset) {
-    return isset($this->attrs[$offset]);
-  }
-
-  public function offsetUnset($offset) {
-    unset($this->attrs[$offset]);
-  }
-
-  public function offsetGet($offset) {
-    return (isset($this->attrs[$offset]) ? $this->attrs[$offset] : NULL);
-  }
-
-  public function getPid()
-  {
-    return $this->listing->pid;
-  }
-}
-
 /*!
  * \brief This class handles the entries list for a management instance
  */
@@ -167,8 +125,6 @@ class managementListing
   //~ var $departmentBrowser      = FALSE;
   //~ var $departmentRootVisible  = FALSE;
   public $multiSelect            = TRUE;
-  //~ var $template;
-  //~ var $headline;
   protected $base;
 
   protected $sortDirection  = NULL;
@@ -263,6 +219,8 @@ class managementListing
     foreach ($this->columns as $column) {
       $column->setParent($this);
     }
+
+    $this->columns[1]->setTemplateAttribute('cn');
   }
 
   /*!
@@ -467,36 +425,6 @@ class managementListing
     $result .= '</script>';
 
     return $result;
-
-    //~ $smarty = get_smarty();
-    //~ $smarty->assign("usePrototype", "true");
-    //~ $smarty->assign("FILTER", $this->filter->render());
-    //~ $smarty->assign("SIZELIMIT", print_sizelimit_warning());
-    //~ $smarty->assign("LIST", $result);
-    //~ $smarty->assign("MULTISELECT", $this->multiSelect);
-
-    //~ // Assign navigation elements
-    //~ $nav = $this->renderNavigation();
-    //~ foreach ($nav as $key => $html) {
-      //~ $smarty->assign($key, $html);
-    //~ }
-
-    //~ // Assign action menu / base
-    //~ $smarty->assign("ACTIONS", $this->renderActionMenu());
-    //~ $smarty->assign("BASE", $this->renderBase());
-
-    //~ // Assign summary
-    //~ $smarty->assign("HEADLINE", $this->headline);
-
-    //~ // Try to load template from plugin the folder first...
-    //~ $file = get_template_path($this->xmlData['definition']['template'], TRUE);
-
-    //~ // ... if this fails, try to load the file from the theme folder.
-    //~ if (!file_exists($file)) {
-      //~ $file = get_template_path($this->xmlData['definition']['template']);
-    //~ }
-
-    //~ return $smarty->fetch($file);
   }
 
   /*!
@@ -617,6 +545,15 @@ class managementListing
       foreach ($entries as $dn => $entry) {
         $this->entries[$dn] = new ListingEntry($this, $type, $dn, $entry, $row++);
       }
+
+      if (!$this->parent::$skipTemplates) {
+        $entries = objects::ls($type, $attrsAsked, 'ou=templates,'.$base, '', TRUE, 'one', TRUE);
+
+        $this->objectTypeCount['template_'.$type] = count($entries);
+        foreach ($entries as $dn => $entry) {
+          $this->entries[$dn] = new ListingEntry($this, 'template_'.$type, $dn, $entry, $row++);
+        }
+      }
     }
     /* Store the order of the entries to access them by index later */
     $this->entriesIndex = array_keys($this->entries);
diff --git a/plugins/admin/users/class_userManagement.inc b/plugins/admin/users/class_userManagement.inc
index af2c2d11445ed4d196437dbe0e394df79dfed207..b4471d766e8a27c7522aa5a0d540f0bee207d5dd 100644
--- a/plugins/admin/users/class_userManagement.inc
+++ b/plugins/admin/users/class_userManagement.inc
@@ -82,7 +82,7 @@ class LockAction extends Action
     }
 
     // Skip the entry completely if there's no permission to execute it
-    if (!$this->hasPermission($entry->dn, $entry->type)) {
+    if (!$this->hasPermission($entry->dn, $entry->getTemplatedType(), $entry->isTemplate())) {
       return '<img src="images/empty.png" alt=" " class="center optional"/>';
     }
 
@@ -104,6 +104,8 @@ class userManagement extends management
 {
   public $neededAttrs = array('userPassword' => '1');
 
+  public static $skipTemplates = FALSE;
+
   static function plInfo()
   {
     return array(