diff --git a/app/Entities/Entity.php b/app/Entities/Entity.php
index 7917f83f8..d648f68e4 100644
--- a/app/Entities/Entity.php
+++ b/app/Entities/Entity.php
@@ -102,6 +102,11 @@ class Entity extends Ownable
         return $this->morphMany(View::class, 'viewable');
     }
 
+    public function viewCountQuery()
+    {
+        return $this->views()->selectRaw('viewable_id, sum(views) as view_count')->groupBy('viewable_id');
+    }
+
     /**
      * Get the Tag models that have been user assigned to this entity.
      * @return \Illuminate\Database\Eloquent\Relations\MorphMany
diff --git a/app/Entities/Repos/EntityRepo.php b/app/Entities/Repos/EntityRepo.php
index 44fb9ad12..13a9d9a9c 100644
--- a/app/Entities/Repos/EntityRepo.php
+++ b/app/Entities/Repos/EntityRepo.php
@@ -15,6 +15,7 @@ use BookStack\Exceptions\NotFoundException;
 use BookStack\Exceptions\NotifyException;
 use BookStack\Uploads\AttachmentService;
 use DOMDocument;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Http\Request;
 use Illuminate\Support\Collection;
 
@@ -179,11 +180,27 @@ class EntityRepo
      * Get all entities in a paginated format
      * @param $type
      * @param int $count
+     * @param string $sort
+     * @param string $order
      * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
      */
-    public function getAllPaginated($type, $count = 10)
+    public function getAllPaginated($type, int $count = 10, string $sort = 'name', string $order = 'asc')
     {
-        return $this->entityQuery($type)->orderBy('name', 'asc')->paginate($count);
+        $query = $this->entityQuery($type);
+        $query = $this->addSortToQuery($query, $sort, $order);
+        return $query->paginate($count);
+    }
+
+    protected function addSortToQuery(Builder $query, string $sort = 'name', string $order = 'asc')
+    {
+        $order = ($order === 'asc') ? 'asc' : 'desc';
+        $propertySorts = ['name', 'created_at', 'updated_at'];
+
+        if (in_array($sort, $propertySorts)) {
+            return $query->orderBy($sort, $order);
+        }
+
+        return $query;
     }
 
     /**
diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php
index 44368a9c4..b5e2a4a85 100644
--- a/app/Http/Controllers/BookController.php
+++ b/app/Http/Controllers/BookController.php
@@ -36,18 +36,30 @@ class BookController extends Controller
      */
     public function index()
     {
-        $books = $this->entityRepo->getAllPaginated('book', 18);
+        $view = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books'));
+        $sort = setting()->getUser($this->currentUser, 'books_sort', 'name');
+        $order = setting()->getUser($this->currentUser, 'books_sort_order', 'asc');
+        $sortOptions = [
+            'name' => trans('common.sort_name'),
+            'created_at' => trans('common.sort_created_at'),
+            'updated_at' => trans('common.sort_updated_at'),
+        ];
+
+        $books = $this->entityRepo->getAllPaginated('book', 18, $sort, $order);
         $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
         $popular = $this->entityRepo->getPopular('book', 4, 0);
         $new = $this->entityRepo->getRecentlyCreated('book', 4, 0);
-        $booksViewType = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books', 'list'));
+
         $this->setPageTitle(trans('entities.books'));
         return view('books/index', [
             'books' => $books,
             'recents' => $recents,
             'popular' => $popular,
             'new' => $new,
-            'booksViewType' => $booksViewType
+            'view' => $view,
+            'sort' => $sort,
+            'order' => $order,
+            'sortOptions' => $sortOptions,
         ]);
     }
 
diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php
index 80f567eaa..fc4f184fc 100644
--- a/app/Http/Controllers/Controller.php
+++ b/app/Http/Controllers/Controller.php
@@ -123,6 +123,20 @@ abstract class Controller extends BaseController
         return true;
     }
 
+    /**
+     * Check if the current user has a permission or bypass if the provided user
+     * id matches the current user.
+     * @param string $permissionName
+     * @param int $userId
+     * @return bool
+     */
+    protected function checkPermissionOrCurrentUser(string $permissionName, int $userId)
+    {
+        return $this->checkPermissionOr($permissionName, function() use ($userId) {
+            return $userId === $this->currentUser->id;
+        });
+    }
+
     /**
      * Send back a json error message.
      * @param string $messageText
diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
index 5f5c8365e..92dc3cdaa 100644
--- a/app/Http/Controllers/UserController.php
+++ b/app/Http/Controllers/UserController.php
@@ -247,19 +247,7 @@ class UserController extends Controller
      */
     public function switchBookView($id, Request $request)
     {
-        $this->checkPermissionOr('users-manage', function () use ($id) {
-            return $this->currentUser->id == $id;
-        });
-
-        $viewType = $request->get('view_type');
-        if (!in_array($viewType, ['grid', 'list'])) {
-            $viewType = 'list';
-        }
-
-        $user = $this->user->findOrFail($id);
-        setting()->putUser($user, 'books_view_type', $viewType);
-
-        return redirect()->back(302, [], "/settings/users/$id");
+        return $this->switchViewType($id, $request, 'books');
     }
 
     /**
@@ -270,18 +258,72 @@ class UserController extends Controller
      */
     public function switchShelfView($id, Request $request)
     {
-        $this->checkPermissionOr('users-manage', function () use ($id) {
-            return $this->currentUser->id == $id;
-        });
+        return $this->switchViewType($id, $request, 'bookshelves');
+    }
+
+    /**
+     * For a type of list, switch with stored view type for a user.
+     * @param integer $userId
+     * @param Request $request
+     * @param string $listName
+     * @return \Illuminate\Http\RedirectResponse
+     */
+    protected function switchViewType($userId, Request $request, string $listName)
+    {
+        $this->checkPermissionOrCurrentUser('users-manage', $userId);
 
         $viewType = $request->get('view_type');
         if (!in_array($viewType, ['grid', 'list'])) {
             $viewType = 'list';
         }
 
-        $user = $this->user->findOrFail($id);
-        setting()->putUser($user, 'bookshelves_view_type', $viewType);
+        $user = $this->user->findOrFail($userId);
+        $key = $listName . '_view_type';
+        setting()->putUser($user, $key, $viewType);
 
-        return redirect()->back(302, [], "/settings/users/$id");
+        return redirect()->back(302, [], "/settings/users/$userId");
     }
+
+    /**
+     * Change the stored sort type for the books view.
+     * @param $id
+     * @param Request $request
+     * @return \Illuminate\Http\RedirectResponse
+     */
+    public function changeBooksSort($id, Request $request)
+    {
+        // TODO - Test this endpoint
+        return $this->changeListSort($id, $request, 'books');
+    }
+
+    /**
+     * Changed the stored preference for a list sort order.
+     * @param int $userId
+     * @param Request $request
+     * @param string $listName
+     * @return \Illuminate\Http\RedirectResponse
+     */
+    protected function changeListSort(int $userId, Request $request, string $listName)
+    {
+        $this->checkPermissionOrCurrentUser('users-manage', $userId);
+
+        $sort = $request->get('sort');
+        if (!in_array($sort, ['name', 'created_at', 'updated_at'])) {
+            $sort = 'name';
+        }
+
+        $order = $request->get('order');
+        if (!in_array($order, ['asc', 'desc'])) {
+            $order = 'asc';
+        }
+
+        $user = $this->user->findOrFail($userId);
+        $sortKey = $listName . '_sort';
+        $orderKey = $listName . '_sort_order';
+        setting()->putUser($user, $sortKey, $sort);
+        setting()->putUser($user, $orderKey, $order);
+
+        return redirect()->back(302, [], "/settings/users/$userId");
+    }
+
 }
diff --git a/app/Settings/SettingService.php b/app/Settings/SettingService.php
index c903bd60a..42a381060 100644
--- a/app/Settings/SettingService.php
+++ b/app/Settings/SettingService.php
@@ -60,6 +60,9 @@ class SettingService
      */
     public function getUser($user, $key, $default = false)
     {
+        if ($user->isDefault()) {
+            return session()->get($key, $default);
+        }
         return $this->get($this->userKey($user->id, $key), $default);
     }
 
@@ -179,6 +182,9 @@ class SettingService
      */
     public function putUser($user, $key, $value)
     {
+        if ($user->isDefault()) {
+            return session()->put($key, $value);
+        }
         return $this->put($this->userKey($user->id, $key), $value);
     }
 
diff --git a/resources/assets/js/components/index.js b/resources/assets/js/components/index.js
index 7007b5878..dd1d95a31 100644
--- a/resources/assets/js/components/index.js
+++ b/resources/assets/js/components/index.js
@@ -19,6 +19,7 @@ import pageDisplay from "./page-display";
 import shelfSort from "./shelf-sort";
 import homepageControl from "./homepage-control";
 import headerMobileToggle from "./header-mobile-toggle";
+import listSortControl from "./list-sort-control";
 
 
 const componentMapping = {
@@ -42,7 +43,8 @@ const componentMapping = {
     'page-display': pageDisplay,
     'shelf-sort': shelfSort,
     'homepage-control': homepageControl,
-     'header-mobile-toggle': headerMobileToggle,
+    'header-mobile-toggle': headerMobileToggle,
+    'list-sort-control': listSortControl,
 };
 
 window.components = {};
diff --git a/resources/assets/js/components/list-sort-control.js b/resources/assets/js/components/list-sort-control.js
new file mode 100644
index 000000000..d463ed0b7
--- /dev/null
+++ b/resources/assets/js/components/list-sort-control.js
@@ -0,0 +1,42 @@
+/**
+ * ListSortControl
+ * Manages the logic for the control which provides list sorting options.
+ */
+class ListSortControl {
+
+    constructor(elem) {
+        this.elem = elem;
+
+        this.sortInput = elem.querySelector('[name="sort"]');
+        this.orderInput = elem.querySelector('[name="order"]');
+        this.form = elem.querySelector('form');
+
+        this.elem.addEventListener('click', event => {
+            if (event.target.closest('[data-sort-value]') !== null) {
+                this.sortOptionClick(event);
+            }
+            if (event.target.closest('[data-sort-dir]') !== null) {
+                this.sortDirectionClick(event);
+            }
+        })
+
+    }
+
+    sortOptionClick(event) {
+        const sortOption = event.target.closest('[data-sort-value]');
+        this.sortInput.value = sortOption.getAttribute('data-sort-value');
+        event.preventDefault();
+        this.form.submit();
+    }
+
+    sortDirectionClick(event) {
+        const currentDir = this.orderInput.value;
+        const newDir = (currentDir === 'asc') ? 'desc' : 'asc';
+        this.orderInput.value = newDir;
+        event.preventDefault();
+        this.form.submit();
+    }
+
+}
+
+export default ListSortControl;
\ No newline at end of file
diff --git a/resources/assets/sass/_lists.scss b/resources/assets/sass/_lists.scss
index 74d32e143..55104680a 100644
--- a/resources/assets/sass/_lists.scss
+++ b/resources/assets/sass/_lists.scss
@@ -369,6 +369,9 @@ ul.pagination {
     padding: $-xs $-m;
     line-height: 1.2;
   }
+  li.active a {
+    font-weight: 600;
+  }
   a, button {
     display: block;
     padding: $-xs $-m;
diff --git a/resources/assets/sass/styles.scss b/resources/assets/sass/styles.scss
index ff88cb1d4..7792aee83 100644
--- a/resources/assets/sass/styles.scss
+++ b/resources/assets/sass/styles.scss
@@ -258,6 +258,9 @@ $btt-size: 40px;
 
 .list-sort-container {
   display: inline-block;
+  form {
+    display: inline-block;
+  }
   .list-sort {
     display: inline-grid;
     margin-left: $-s;
diff --git a/resources/lang/en/common.php b/resources/lang/en/common.php
index 8e86129e2..3e42c9feb 100644
--- a/resources/lang/en/common.php
+++ b/resources/lang/en/common.php
@@ -40,6 +40,13 @@ return [
     'remove' => 'Remove',
     'add' => 'Add',
 
+    /**
+     * Sort Options
+     */
+    'sort_name' => 'Name',
+    'sort_created_at' => 'Created Date',
+    'sort_updated_at' => 'Updated Date',
+
     /**
      * Misc
      */
diff --git a/resources/views/books/index.blade.php b/resources/views/books/index.blade.php
index b1998da3b..3cf1a10bf 100644
--- a/resources/views/books/index.blade.php
+++ b/resources/views/books/index.blade.php
@@ -28,7 +28,7 @@
 @stop
 
 @section('body')
-    @include('books.list', ['books' => $books, 'bookViewType' => $booksViewType])
+    @include('books.list', ['books' => $books, 'view' => $view])
 @stop
 
 @section('right')
@@ -42,7 +42,7 @@
                     <span>{{ trans('entities.books_create') }}</span>
                 </a>
             @endif
-            @include('books.view-toggle', ['booksViewType' => $booksViewType])
+            @include('books.view-toggle', ['view' => $view])
         </div>
     </div>
 
diff --git a/resources/views/books/list.blade.php b/resources/views/books/list.blade.php
index 0e5f5c887..2155cd5c8 100644
--- a/resources/views/books/list.blade.php
+++ b/resources/views/books/list.blade.php
@@ -1,30 +1,15 @@
 
-<div class="content-wrap card {{ $booksViewType === 'list' ? 'thin' : '' }}">
+<div class="content-wrap card {{ $view === 'list' ? 'thin' : '' }}">
     <div class="grid halves v-center">
         <h1 class="list-heading">{{ trans('entities.books') }}</h1>
         <div class="text-right">
 
-            <div class="list-sort-container">
-                <div class="list-sort-label">Sort</div>
-                <div class="list-sort">
-                    <div class="list-sort-type dropdown-container" dropdown>
-                        <div dropdown-toggle>Name</div>
-                        <ul>
-                            <li><a href="#">Name</a></li>
-                            <li><a href="#">Created Date</a></li>
-                            <li><a href="#">Popularity</a></li>
-                        </ul>
-                    </div>
-                    <div class="list-sort-dir">
-                        @icon('sort-up')
-                    </div>
-                </div>
-            </div>
+            @include('partials.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort])
 
         </div>
     </div>
     @if(count($books) > 0)
-        @if($booksViewType === 'list')
+        @if($view === 'list')
             <div class="entity-list">
                 @foreach($books as $book)
                     <a href="{{ $book->getUrl() }}" class="book entity-list-item" data-entity-type="book" data-entity-id="{{$book->id}}">
diff --git a/resources/views/books/view-toggle.blade.php b/resources/views/books/view-toggle.blade.php
index eb1464b02..c0f8b3f15 100644
--- a/resources/views/books/view-toggle.blade.php
+++ b/resources/views/books/view-toggle.blade.php
@@ -2,8 +2,8 @@
     <form action="{{ baseUrl("/settings/users/{$currentUser->id}/switch-book-view") }}" method="POST" class="inline">
         {!! csrf_field() !!}
         {!! method_field('PATCH') !!}
-        <input type="hidden" value="{{ $booksViewType === 'list'? 'grid' : 'list' }}" name="view_type">
-        @if ($booksViewType === 'list')
+        <input type="hidden" value="{{ $view === 'list'? 'grid' : 'list' }}" name="view_type">
+        @if ($view === 'list')
             <a onclick="this.closest('form').submit()" type="submit" class="icon-list-item">
                 <span class="icon">@icon('grid')</span>
                 <span>{{ trans('common.grid_view') }}</span>
diff --git a/resources/views/partials/sort.blade.php b/resources/views/partials/sort.blade.php
new file mode 100644
index 000000000..03eab8487
--- /dev/null
+++ b/resources/views/partials/sort.blade.php
@@ -0,0 +1,32 @@
+<?php
+    $selectedSort = (isset($sort) && array_key_exists($sort, $options)) ? $sort : array_keys($options)[0];
+    $order = (isset($order) && in_array($order, ['asc', 'desc'])) ? $order : 'asc';
+?>
+<div class="list-sort-container" list-sort-control>
+    <div class="list-sort-label">{{ trans('common.sort') }}</div>
+    <form action="{{ baseUrl("/settings/users/{$currentUser->id}/change-books-sort") }}" method="post">
+
+        {!! csrf_field() !!}
+        {!! method_field('PATCH') !!}
+        <input type="hidden" value="{{ $selectedSort }}" name="sort">
+        <input type="hidden" value="{{ $order }}" name="order">
+
+        <div class="list-sort">
+            <div class="list-sort-type dropdown-container" dropdown>
+                <div dropdown-toggle>{{ $options[$selectedSort] }}</div>
+                <ul>
+                    @foreach($options as $key => $label)
+                        <li @if($key === $selectedSort) class="active" @endif><a href="#" data-sort-value="{{$key}}">{{ $label }}</a></li>
+                    @endforeach
+                </ul>
+            </div>
+            <div class="list-sort-dir" data-sort-dir>
+                @if($order === 'desc')
+                    @icon('sort-up')
+                @else
+                    @icon('sort-down')
+                @endif
+            </div>
+        </div>
+    </form>
+</div>
\ No newline at end of file
diff --git a/routes/web.php b/routes/web.php
index d3c5f46d3..bfdd0e580 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -176,6 +176,7 @@ Route::group(['middleware' => 'auth'], function () {
         Route::get('/users/{id}/delete', 'UserController@delete');
         Route::patch('/users/{id}/switch-book-view', 'UserController@switchBookView');
         Route::patch('/users/{id}/switch-shelf-view', 'UserController@switchShelfView');
+        Route::patch('/users/{id}/change-books-sort', 'UserController@changeBooksSort');
         Route::post('/users/create', 'UserController@store');
         Route::get('/users/{id}', 'UserController@edit');
         Route::put('/users/{id}', 'UserController@update');