diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx
index 0c0973f2bb3ea4843ff5788e9c6e36863681c94d..29a26c8bd3180a02f7414476e1ed00f05d92bd8a 100644
--- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx
@@ -81,7 +81,13 @@ const renderComponent = (
 
 describe('LayerImageObjectEditFactoryModal - component', () => {
   it('should render LayerImageObjectEditFactoryModal component with initial state', () => {
-    renderComponent();
+    renderComponent({
+      activeAction: null,
+      layerObject: {
+        ...layerImageFixture,
+        glyph: null,
+      },
+    });
 
     expect(screen.getByText(/Glyph:/i)).toBeInTheDocument();
     expect(screen.getByText(/File:/i)).toBeInTheDocument();
@@ -90,7 +96,13 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
   });
 
   it('should display a list of glyphs in the dropdown', async () => {
-    renderComponent();
+    renderComponent({
+      activeAction: null,
+      layerObject: {
+        ...layerImageFixture,
+        glyph: null,
+      },
+    });
 
     const dropdown = screen.getByTestId('autocomplete');
     if (!dropdown.firstChild) {
@@ -102,7 +114,13 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
   });
 
   it('should update the selected glyph on dropdown change', async () => {
-    renderComponent();
+    renderComponent({
+      activeAction: null,
+      layerObject: {
+        ...layerImageFixture,
+        glyph: null,
+      },
+    });
 
     const dropdown = screen.getByTestId('autocomplete');
     if (!dropdown.firstChild) {
@@ -142,13 +160,13 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
     };
     const getGlyphDataMock = jest.fn(() => glyphData);
     jest.spyOn(layerObjectFeature, 'get').mockImplementation(key => {
-      if (key === 'update') return (): void => {};
-      if (key === 'getGlyphData') return getGlyphDataMock;
+      if (key === 'updateElement') return (): void => {};
+      if (key === 'getObjectData') return getGlyphDataMock;
       return undefined;
     });
     renderComponent({
       activeAction: MAP_EDIT_ACTIONS.TRANSFORM_IMAGE,
-      layerImageObject: glyphData,
+      layerObject: glyphData,
     });
 
     const submitButton = screen.getByText(/Submit/i);
@@ -164,7 +182,13 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
   });
 
   it('should display "No Image" when there is no image file', () => {
-    const { store } = renderComponent();
+    const { store } = renderComponent({
+      activeAction: null,
+      layerObject: {
+        ...layerImageFixture,
+        glyph: null,
+      },
+    });
 
     store.dispatch({
       type: 'glyphs/clearGlyphData',
diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.tsx
index e4dfcdd01a2d83fe449f515152ec47c68b592ce1..dc2808459cdd66ba4f4c85b000a1d7f30cc55d94 100644
--- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.tsx
+++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.tsx
@@ -2,7 +2,7 @@
 import React, { useState } from 'react';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 
-import { mapEditToolsLayerImageObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
+import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
 import { LayerImageObjectForm } from '@/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectForm.component';
 import { currentModelIdSelector } from '@/redux/models/models.selectors';
 import { addGlyph } from '@/redux/glyphs/glyphs.thunks';
@@ -13,24 +13,25 @@ import { showToast } from '@/utils/showToast';
 import { closeModal } from '@/redux/modal/modal.slice';
 import { SerializedError } from '@reduxjs/toolkit';
 import { useMapInstance } from '@/utils/context/mapInstanceContext';
-import updateGlyph from '@/components/Map/MapViewer/utils/shapes/elements/Glyph/updateGlyph';
+import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement';
 import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
 
 export const LayerImageObjectEditFactoryModal: React.FC = () => {
-  const layerImageObject = useAppSelector(mapEditToolsLayerImageObjectSelector);
+  const layerObject = useAppSelector(mapEditToolsLayerObjectSelector);
   const { mapInstance } = useMapInstance();
 
+  if (!layerObject || !('glyph' in layerObject)) {
+    throw new Error('Invalid layer image object');
+  }
   const currentModelId = useAppSelector(currentModelIdSelector);
   const dispatch = useAppDispatch();
 
-  const [selectedGlyph, setSelectedGlyph] = useState<number | null>(
-    layerImageObject?.glyph || null,
-  );
+  const [selectedGlyph, setSelectedGlyph] = useState<number | null>(layerObject?.glyph || null);
   const [file, setFile] = useState<File | null>(null);
   const [isSending, setIsSending] = useState<boolean>(false);
 
   const handleSubmit = async (): Promise<void> => {
-    if (!layerImageObject) {
+    if (!layerObject) {
       return;
     }
     setIsSending(true);
@@ -47,8 +48,8 @@ export const LayerImageObjectEditFactoryModal: React.FC = () => {
       const layerImage = await dispatch(
         updateLayerImageObject({
           modelId: currentModelId,
-          layerId: layerImageObject.layer,
-          ...layerImageObject,
+          layerId: layerObject.layer,
+          ...layerObject,
           glyph: glyphId,
         }),
       ).unwrap();
@@ -57,7 +58,7 @@ export const LayerImageObjectEditFactoryModal: React.FC = () => {
           layerUpdateImage({ modelId: currentModelId, layerId: layerImage.layer, layerImage }),
         );
         dispatch(mapEditToolsSetLayerObject(layerImage));
-        updateGlyph(mapInstance, layerImage.layer, layerImage);
+        updateElement(mapInstance, layerImage.layer, layerImage);
       }
       showToast({
         type: 'success',
diff --git a/src/components/Map/Drawer/LayersDrawer/LayerDrawerTextItem.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayerDrawerTextItem.component.tsx
index 12a7959c686d19332358bbb886f6dd9bba463aa3..6f57c76263e042ba0009c55879578125496cdaae 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayerDrawerTextItem.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayerDrawerTextItem.component.tsx
@@ -1,18 +1,80 @@
-import { JSX } from 'react';
+import React, { JSX, useMemo } from 'react';
 import { LayerText } from '@/types/models';
 import { Icon } from '@/shared/Icon';
+import { LayersDrawerObjectActions } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerObjectActions.component';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
+import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors';
 
 interface LayersDrawerTextItemProps {
   layerText: LayerText;
+  bringToFront: () => void;
+  bringToBack: () => void;
+  removeObject: () => void;
+  centerObject: () => void;
+  editObject: () => void;
+  isLayerVisible: boolean;
+  isLayerActive: boolean;
 }
 
 export const LayersDrawerTextItem = ({
   layerText,
+  bringToFront,
+  bringToBack,
+  removeObject,
+  centerObject,
+  editObject,
+  isLayerVisible,
+  isLayerActive,
 }: LayersDrawerTextItemProps): JSX.Element | null => {
+  const dispatch = useAppDispatch();
+  const activeLayerObject = useAppSelector(mapEditToolsLayerObjectSelector);
+  const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector);
+
+  const showActions = useMemo(() => {
+    return activeLayerObject?.id === layerText.id;
+  }, [activeLayerObject?.id, layerText.id]);
+
+  const canSelectItem = useMemo(() => {
+    return isLayerVisible && isLayerActive && hasPrivilegeToWriteProject;
+  }, [isLayerVisible, isLayerActive, hasPrivilegeToWriteProject]);
+
+  const selectItem = useMemo(() => {
+    return (): void => {
+      if (canSelectItem) {
+        dispatch(mapEditToolsSetLayerObject(layerText));
+      }
+    };
+  }, [canSelectItem, dispatch, layerText]);
+
+  const handleKeyPress = (): void => {};
+
   return (
-    <div className="flex min-h-[24px]  gap-2">
-      <Icon name="text" className="shrink-0" />
-      <span className="truncate">{layerText.notes}</span>
+    <div
+      className="flex min-h-[24px] items-center justify-between gap-2"
+      id={`layer-text-item-${layerText.id}`}
+    >
+      <div
+        className={`flex gap-2 ${canSelectItem ? 'cursor-pointer' : 'cursor-default'}`}
+        onClick={selectItem}
+        tabIndex={0}
+        onKeyDown={handleKeyPress}
+        role="button"
+      >
+        <Icon name="text" className="shrink-0" />
+        <span className="truncate">{layerText.notes}</span>
+      </div>
+      {showActions && (
+        <LayersDrawerObjectActions
+          bringToFront={bringToFront}
+          bringToBack={bringToBack}
+          removeObject={removeObject}
+          centerObject={centerObject}
+          editObject={editObject}
+        />
+      )}
     </div>
   );
 };
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
index df941aca918455a3b099da92866c2e5d9748f7a5..12bef081cb69be66edc08ac8bdf2eb448540ce31 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
@@ -8,14 +8,14 @@ import { JSX, useEffect, useRef } from 'react';
 import { openLayerFactoryModal } from '@/redux/modal/modal.slice';
 import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors';
 import { LayersDrawerLayer } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerLayer.component';
-import { mapEditToolsLayerImageObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
+import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
 
 export const LayersDrawer = (): JSX.Element => {
   const layersForCurrentModel = useAppSelector(layersForCurrentModelSelector);
   const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector);
   const dispatch = useAppDispatch();
   const layersDrawerRef = useRef<HTMLDivElement>(null);
-  const mapEditToolsLayerImageObject = useAppSelector(mapEditToolsLayerImageObjectSelector);
+  const mapEditToolsLayerImageObject = useAppSelector(mapEditToolsLayerObjectSelector);
 
   const addNewLayer = (): void => {
     dispatch(openLayerFactoryModal());
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerImageItem.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerImageItem.component.tsx
index d2884a5bb104b64d6d5f30105d5f3afc84a13bec..0622f1416bb018d4192399beb33bf26b4f0bf0fe 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerImageItem.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerImageItem.component.tsx
@@ -4,7 +4,7 @@ import { Icon } from '@/shared/Icon';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { glyphFileNameByIdSelector } from '@/redux/glyphs/glyphs.selectors';
 import { LayersDrawerObjectActions } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerObjectActions.component';
-import { mapEditToolsLayerImageObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
+import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
 import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors';
@@ -31,7 +31,7 @@ export const LayersDrawerImageItem = ({
   isLayerActive,
 }: LayersDrawerImageItemProps): JSX.Element | null => {
   const dispatch = useAppDispatch();
-  const activeLayerImage = useAppSelector(mapEditToolsLayerImageObjectSelector);
+  const activeLayerImage = useAppSelector(mapEditToolsLayerObjectSelector);
   const fileName = useAppSelector(state => glyphFileNameByIdSelector(state, layerImage.glyph));
   const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector);
 
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx
index fca7a858abf3d7658a6b63415d8eeea9bcf46636..fa98e051392758b8139aa334988c37a98a8f0aef 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx
@@ -9,19 +9,23 @@ import { JSX, useState } from 'react';
 import { LayersDrawerImageItem } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerImageItem.component';
 import { LayersDrawerTextItem } from '@/components/Map/Drawer/LayersDrawer/LayerDrawerTextItem.component';
 import QuestionModal from '@/components/FunctionalArea/Modal/QuestionModal/QustionModal.component';
-import { removeLayerImage, updateLayerImageObject } from '@/redux/layers/layers.thunks';
-import { layerDeleteImage, layerUpdateImage } from '@/redux/layers/layers.slice';
+import {
+  removeLayerImage,
+  removeLayerText,
+  updateLayerImageObject,
+} from '@/redux/layers/layers.thunks';
+import { layerDeleteImage, layerDeleteText, layerUpdateImage } from '@/redux/layers/layers.slice';
 import removeElementFromLayer from '@/components/Map/MapViewer/utils/shapes/elements/removeElementFromLayer';
 import { showToast } from '@/utils/showToast';
 import { SerializedError } from '@reduxjs/toolkit';
-import { LayerImage } from '@/types/models';
+import { LayerImage, LayerText } from '@/types/models';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { useMapInstance } from '@/utils/context/mapInstanceContext';
 import { mapModelIdSelector } from '@/redux/map/map.selectors';
 import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
-import updateGlyph from '@/components/Map/MapViewer/utils/shapes/elements/Glyph/updateGlyph';
+import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement';
 import { useSetBounds } from '@/utils/map/useSetBounds';
-import { mapEditToolsLayerImageObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
+import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
 import { usePointToProjection } from '@/utils/map/usePointToProjection';
 import { Coordinate } from 'ol/coordinate';
 import { openLayerImageObjectEditFactoryModal } from '@/redux/modal/modal.slice';
@@ -32,6 +36,19 @@ interface LayersDrawerObjectsListProps {
   isLayerActive: boolean;
 }
 
+const removeObjectConfig = {
+  image: {
+    question: 'Are you sure you want to remove the image?',
+    successMessage: 'The layer image has been successfully removed',
+    errorMessage: 'An error occurred while removing the layer text',
+  },
+  text: {
+    question: 'Are you sure you want to remove the text?',
+    successMessage: 'The layer text has been successfully removed',
+    errorMessage: 'An error occurred while removing the layer text',
+  },
+};
+
 export const LayersDrawerObjectsList = ({
   layerId,
   isLayerVisible,
@@ -41,57 +58,81 @@ export const LayersDrawerObjectsList = ({
   const highestZIndex = useAppSelector(highestZIndexSelector);
   const lowestZIndex = useAppSelector(lowestZIndexSelector);
   const layer = useAppSelector(state => layerByIdSelector(state, layerId));
-  const mapEditToolsLayerImageObject = useAppSelector(mapEditToolsLayerImageObjectSelector);
-  const [isImageRemoveModalOpen, setIsImageRemoveModalOpen] = useState(false);
-  const [layerImageToRemove, setLayerImageToRemove] = useState<LayerImage | null>(null);
+  const mapEditToolsLayerImageObject = useAppSelector(mapEditToolsLayerObjectSelector);
+  const [removeModalState, setRemoveModalState] = useState<undefined | 'text' | 'image'>(undefined);
+  const [layerObjectToRemove, setLayerObjectToRemove] = useState<LayerImage | LayerText | null>(
+    null,
+  );
   const dispatch = useAppDispatch();
   const setBounds = useSetBounds();
   const pointToProjection = usePointToProjection();
   const { mapInstance } = useMapInstance();
 
-  const removeImage = (layerImage: LayerImage): void => {
-    setLayerImageToRemove(layerImage);
-    setIsImageRemoveModalOpen(true);
+  const removeObject = (layerObject: LayerImage | LayerText): void => {
+    setLayerObjectToRemove(layerObject);
+    if ('glyph' in layerObject) {
+      setRemoveModalState('image');
+    } else {
+      setRemoveModalState('text');
+    }
   };
 
-  const rejectImageRemove = (): void => {
-    setIsImageRemoveModalOpen(false);
+  const rejectRemove = (): void => {
+    setRemoveModalState(undefined);
   };
 
-  const confirmImageRemove = async (): Promise<void> => {
-    if (!layerImageToRemove) {
+  const confirmRemove = async (): Promise<void> => {
+    if (!layerObjectToRemove || !removeModalState) {
       return;
     }
+
     try {
-      await dispatch(
-        removeLayerImage({
-          modelId: currentModelId,
-          layerId: layerImageToRemove.layer,
-          imageId: layerImageToRemove.id,
-        }),
-      ).unwrap();
-      dispatch(
-        layerDeleteImage({
-          modelId: currentModelId,
-          layerId: layerImageToRemove.layer,
-          imageId: layerImageToRemove.id,
-        }),
-      );
+      if (removeModalState === 'text') {
+        await dispatch(
+          removeLayerText({
+            modelId: currentModelId,
+            layerId: layerObjectToRemove.layer,
+            textId: layerObjectToRemove.id,
+          }),
+        ).unwrap();
+        dispatch(
+          layerDeleteText({
+            modelId: currentModelId,
+            layerId: layerObjectToRemove.layer,
+            textId: layerObjectToRemove.id,
+          }),
+        );
+      } else {
+        await dispatch(
+          removeLayerImage({
+            modelId: currentModelId,
+            layerId: layerObjectToRemove.layer,
+            imageId: layerObjectToRemove.id,
+          }),
+        ).unwrap();
+        dispatch(
+          layerDeleteImage({
+            modelId: currentModelId,
+            layerId: layerObjectToRemove.layer,
+            imageId: layerObjectToRemove.id,
+          }),
+        );
+      }
       removeElementFromLayer({
         mapInstance,
-        layerId: layerImageToRemove.layer,
-        featureId: layerImageToRemove.id,
+        layerId: layerObjectToRemove.layer,
+        featureId: layerObjectToRemove.id,
       });
       showToast({
         type: 'success',
-        message: 'The layer image has been successfully removed',
+        message: removeObjectConfig[removeModalState].successMessage,
       });
-      setIsImageRemoveModalOpen(false);
+      setRemoveModalState(undefined);
     } catch (error) {
       const typedError = error as SerializedError;
       showToast({
         type: 'error',
-        message: typedError.message || 'An error occurred while removing the layer image',
+        message: typedError.message || removeObjectConfig[removeModalState].errorMessage,
       });
     }
   };
@@ -120,7 +161,7 @@ export const LayersDrawerObjectsList = ({
         }),
       );
       dispatch(mapEditToolsSetLayerObject(newLayerImage));
-      updateGlyph(mapInstance, newLayerImage.layer, newLayerImage);
+      updateElement(mapInstance, newLayerImage.layer, newLayerImage);
     }
   };
 
@@ -132,12 +173,12 @@ export const LayersDrawerObjectsList = ({
     await updateImageZIndex({ zIndex: lowestZIndex - 1, layerImage });
   };
 
-  const centerObject = (layerImage: LayerImage): void => {
-    if (mapEditToolsLayerImageObject && mapEditToolsLayerImageObject.id === layerImage.id) {
-      const point1 = pointToProjection({ x: layerImage.x, y: layerImage.y });
+  const centerObject = (layerObject: LayerImage | LayerText): void => {
+    if (mapEditToolsLayerImageObject && mapEditToolsLayerImageObject.id === layerObject.id) {
+      const point1 = pointToProjection({ x: layerObject.x, y: layerObject.y });
       const point2 = pointToProjection({
-        x: layerImage.x + layerImage.width,
-        y: layerImage.y + layerImage.height,
+        x: layerObject.x + layerObject.width,
+        y: layerObject.y + layerObject.height,
       });
       setBounds([point1, point2] as Coordinate[]);
     }
@@ -154,13 +195,27 @@ export const LayersDrawerObjectsList = ({
   return (
     <div className={`${isLayerVisible ? 'opacity-100' : 'opacity-40'} flex flex-col gap-1 ps-3`}>
       <QuestionModal
-        isOpen={isImageRemoveModalOpen}
-        onClose={rejectImageRemove}
-        onConfirm={confirmImageRemove}
-        question="Are you sure you want to remove the image?"
+        isOpen={Boolean(removeModalState)}
+        onClose={rejectRemove}
+        onConfirm={confirmRemove}
+        question={
+          removeModalState
+            ? removeObjectConfig[removeModalState].question
+            : 'Are you sure you want to remove the object'
+        }
       />
       {Object.values(layer.texts).map(layerText => (
-        <LayersDrawerTextItem layerText={layerText} key={layerText.id} />
+        <LayersDrawerTextItem
+          layerText={layerText}
+          key={layerText.id}
+          bringToFront={() => {}}
+          bringToBack={() => {}}
+          removeObject={() => removeObject(layerText)}
+          centerObject={() => centerObject(layerText)}
+          editObject={() => {}}
+          isLayerVisible={isLayerVisible}
+          isLayerActive={isLayerActive}
+        />
       ))}
       {Object.values(layer.images).map(layerImage => (
         <LayersDrawerImageItem
@@ -168,7 +223,7 @@ export const LayersDrawerObjectsList = ({
           key={layerImage.id}
           bringToFront={() => bringImageToFront(layerImage)}
           bringToBack={() => bringImageToBack(layerImage)}
-          removeObject={() => removeImage(layerImage)}
+          removeObject={() => removeObject(layerImage)}
           centerObject={() => centerObject(layerImage)}
           editObject={() => editImage()}
           isLayerVisible={isLayerVisible}
diff --git a/src/components/Map/MapViewer/MapViewer.component.tsx b/src/components/Map/MapViewer/MapViewer.component.tsx
index 0307cf080469c999aa576b3b7710fed9c1fffc67..faf874c1f4c1e4802f5c9f37511723e6d1e05840 100644
--- a/src/components/Map/MapViewer/MapViewer.component.tsx
+++ b/src/components/Map/MapViewer/MapViewer.component.tsx
@@ -1,13 +1,17 @@
 import 'ol/ol.css';
 import { twMerge } from 'tailwind-merge';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import { isMapEditToolsActiveSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
+import {
+  isMapEditToolsActiveSelector,
+  mapEditToolsLayerObjectSelector,
+} from '@/redux/mapEditTools/mapEditTools.selectors';
 import { useOlMap } from './utils/useOlMap';
 import { MAP_VIEWER_ROLE } from './MapViewer.constants';
 
 export const MapViewer = (): JSX.Element => {
   const { mapRef } = useOlMap();
   const isMapEditToolsActive = useAppSelector(isMapEditToolsActiveSelector);
+  const layerObject = useAppSelector(mapEditToolsLayerObjectSelector);
 
   return (
     <div
@@ -15,7 +19,7 @@ export const MapViewer = (): JSX.Element => {
       role={MAP_VIEWER_ROLE}
       className={twMerge(
         'absolute left-[88px] top-[104px] h-[calc(100%-104px)] w-[calc(100%-88px)] bg-white',
-        isMapEditToolsActive ? 'bg-[#e4e2de]' : 'bg-white',
+        isMapEditToolsActive || layerObject ? 'bg-[#e4e2de]' : 'bg-white',
       )}
     />
   );
diff --git a/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts b/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts
index 162d345c015bf0d698b35bb57413bdefc0ed61ea..5e3782938c6cc08f2bc06c077bfe514d06c02201 100644
--- a/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts
+++ b/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts
@@ -16,7 +16,7 @@ import {
 } from '@/redux/layers/layers.selectors';
 import { usePointToProjection } from '@/utils/map/usePointToProjection';
 import { MapInstance } from '@/types/map';
-import { Geometry, LineString, MultiPolygon, Point } from 'ol/geom';
+import { Geometry, LineString, MultiPolygon } from 'ol/geom';
 import Polygon from 'ol/geom/Polygon';
 import Layer from '@/components/Map/MapViewer/utils/shapes/layer/Layer';
 import { arrowTypesSelector, lineTypesSelector } from '@/redux/shapes/shapes.selectors';
@@ -25,7 +25,7 @@ import { mapDataSizeSelector } from '@/redux/map/map.selectors';
 import { LayerState } from '@/redux/layers/layers.types';
 import {
   mapEditToolsActiveActionSelector,
-  mapEditToolsLayerImageObjectSelector,
+  mapEditToolsLayerObjectSelector,
 } from '@/redux/mapEditTools/mapEditTools.selectors';
 import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants';
 import getDrawBoundingBoxInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getDrawBoundingBoxInteraction';
@@ -38,7 +38,7 @@ import {
   mapEditToolsSetActiveAction,
   mapEditToolsSetLayerObject,
 } from '@/redux/mapEditTools/mapEditTools.slice';
-import getTransformImageInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformImageInteraction';
+import getTransformInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction';
 import { useWebSocketEntityUpdatesContext } from '@/utils/websocket-entity-updates/webSocketEntityUpdatesProvider';
 import processMessage from '@/components/Map/MapViewer/utils/websocket/processMessage';
 import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors';
@@ -46,9 +46,7 @@ import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors'
 export const useOlMapAdditionalLayers = (
   mapInstance: MapInstance,
 ): Array<
-  VectorLayer<
-    VectorSource<Feature<Point> | Feature<Polygon> | Feature<LineString> | Feature<MultiPolygon>>
-  >
+  VectorLayer<VectorSource<Feature<Polygon> | Feature<LineString> | Feature<MultiPolygon>>>
 > => {
   const activeAction = useAppSelector(mapEditToolsActiveActionSelector);
   const dispatch = useAppDispatch();
@@ -61,7 +59,7 @@ export const useOlMapAdditionalLayers = (
   const activeLayers = useAppSelector(layersActiveLayersSelector);
   const drawLayer = useAppSelector(layersDrawLayerSelector);
   const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector);
-  const mapEditToolsLayerImageObject = useAppSelector(mapEditToolsLayerImageObjectSelector);
+  const mapEditToolsLayerObject = useAppSelector(mapEditToolsLayerObjectSelector);
 
   const [layersState, setLayersState] = useState<Array<LayerState>>([]);
   const [layersLoadingState, setLayersLoadingState] = useState(false);
@@ -157,21 +155,23 @@ export const useOlMapAdditionalLayers = (
     if (!dispatch || !currentModelId || !activeLayers.length) {
       return null;
     }
-    const imagesFeatures: Array<Feature<Geometry>> = [];
+    const features: Array<Feature<Geometry>> = [];
     const activeVectorLayers = vectorLayers.filter(layer => activeLayers.includes(layer.get('id')));
     activeVectorLayers.forEach(vectorLayer => {
-      imagesFeatures.push(...vectorLayer.get('imagesFeatures'));
+      features.push(...vectorLayer.get('imagesFeatures'));
+      features.push(...vectorLayer.get('textsFeatures'));
     });
-    const imagesFeaturesCollection = new Collection(imagesFeatures);
-    return getTransformImageInteraction(
+    const featuresCollection = new Collection(features);
+    return getTransformInteraction(
       dispatch,
       mapSize,
       currentModelId,
-      imagesFeaturesCollection,
+      featuresCollection,
       restrictionExtent,
     );
   }, [dispatch, mapSize, currentModelId, restrictionExtent, activeLayers, vectorLayers]);
   const transformRef = useRef(transformInteraction);
+
   useEffect(() => {
     transformRef.current = transformInteraction;
   }, [transformInteraction]);
@@ -202,13 +202,13 @@ export const useOlMapAdditionalLayers = (
     }
     const transformFeatures = transformRef.current.getFeatures();
     if (
-      mapEditToolsLayerImageObject &&
+      mapEditToolsLayerObject &&
       (!transformFeatures.getLength() ||
-        transformFeatures.item(0).getId() !== mapEditToolsLayerImageObject.id)
+        transformFeatures.item(0).getId() !== mapEditToolsLayerObject.id)
     ) {
       const layer = vectorLayers.find(vectorLayer => {
         const layerId = vectorLayer.get('id');
-        return layerId === mapEditToolsLayerImageObject.layer;
+        return layerId === mapEditToolsLayerObject.layer;
       });
       if (!layer) {
         return;
@@ -217,13 +217,13 @@ export const useOlMapAdditionalLayers = (
       if (!source) {
         return;
       }
-      const feature = source.getFeatureById(mapEditToolsLayerImageObject.id);
+      const feature = source.getFeatureById(mapEditToolsLayerObject.id);
       if (!feature) {
         return;
       }
       transformRef.current.setSelection(new Collection<Feature>([feature]));
     }
-  }, [mapEditToolsLayerImageObject, vectorLayers]);
+  }, [mapEditToolsLayerObject, vectorLayers]);
 
   useEffect(() => {
     const activeVectorLayers = vectorLayers.filter(layer => {
diff --git a/src/components/Map/MapViewer/utils/shapes/elements/Glyph/Glyph.ts b/src/components/Map/MapViewer/utils/shapes/elements/Glyph/Glyph.ts
index 0dca36a15704c5ca55e6f188fe4d7ec0adcee5e9..342cdfacf7beb2b3b2f46b8494777f88223ca774 100644
--- a/src/components/Map/MapViewer/utils/shapes/elements/Glyph/Glyph.ts
+++ b/src/components/Map/MapViewer/utils/shapes/elements/Glyph/Glyph.ts
@@ -17,7 +17,6 @@ import { LayerImage } from '@/types/models';
 import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
 import getFill from '@/components/Map/MapViewer/utils/shapes/style/getFill';
 import getScaledElementStyle from '@/components/Map/MapViewer/utils/shapes/style/getScaledElementStyle';
-import getBoundingBoxFromExtent from '@/components/Map/MapViewer/utils/shapes/coords/getBoundingBoxFromExtent';
 
 export type GlyphProps = {
   elementId: number;
@@ -154,7 +153,7 @@ export default class Glyph {
 
     this.feature.set('setCoordinates', this.setCoordinates.bind(this));
     this.feature.set('refreshPolygon', this.refreshPolygon.bind(this));
-    this.feature.set('update', this.update.bind(this));
+    this.feature.set('updateElement', this.updateElement.bind(this));
     this.feature.setId(this.elementId);
     this.feature.setStyle(this.getStyle.bind(this));
 
@@ -186,7 +185,7 @@ export default class Glyph {
     this.feature.changed();
   }
 
-  private update(imageObject: LayerImage): void {
+  protected updateElement(imageObject: LayerImage): void {
     this.elementId = imageObject.id;
     this.x = imageObject.x;
     this.y = imageObject.y;
@@ -219,11 +218,6 @@ export default class Glyph {
     const geometry = this.polygonStyle.getGeometry();
     if (geometry && geometry instanceof Polygon) {
       geometry.setCoordinates(coords);
-      const boundingBox = getBoundingBoxFromExtent(geometry.getExtent(), this.mapSize);
-      this.x = boundingBox.x;
-      this.y = boundingBox.y;
-      this.width = boundingBox.width;
-      this.height = boundingBox.height;
     }
   }
 
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts b/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts
index 2149e63b551b9d2ec7a5e42561a2d805b5f8165f..7f697a728a0d69c560730771d4ae182ea95c9ceb 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts
@@ -4,12 +4,12 @@ import {
   LayerLine,
   LayerOval,
   LayerRect,
-  LayerText,
+  LayerText as LayerTextModel,
 } from '@/types/models';
 import { MapInstance } from '@/types/map';
 import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
 import { Feature } from 'ol';
-import { LineString, MultiPolygon, Point } from 'ol/geom';
+import { LineString, MultiPolygon } from 'ol/geom';
 import Polygon from 'ol/geom/Polygon';
 import VectorSource from 'ol/source/Vector';
 import VectorLayer from 'ol/layer/Vector';
@@ -30,11 +30,11 @@ import getArrowFeature from '@/components/Map/MapViewer/utils/shapes/elements/ge
 import getRotation from '@/components/Map/MapViewer/utils/shapes/coords/getRotation';
 import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
 import getEllipseCoords from '@/components/Map/MapViewer/utils/shapes/coords/getEllipseCoords';
-import Text from '@/components/Map/MapViewer/utils/shapes/text/Text';
-import LayerImage from '@/components/Map/MapViewer/utils/shapes/elements/Glyph/LayerImage';
+import LayerText from '@/components/Map/MapViewer/utils/shapes/layer/elements/LayerText';
+import LayerImage from '@/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage';
 
 export interface LayerProps {
-  texts: { [key: string]: LayerText };
+  texts: { [key: string]: LayerTextModel };
   rects: Array<LayerRect>;
   ovals: Array<LayerOval>;
   lines: Array<LayerLine>;
@@ -51,7 +51,7 @@ export interface LayerProps {
 export default class Layer {
   layerId: number;
 
-  texts: { [key: string]: LayerText };
+  texts: { [key: string]: LayerTextModel };
 
   rects: Array<LayerRect>;
 
@@ -71,12 +71,10 @@ export default class Layer {
 
   mapSize: MapSize;
 
-  vectorSource: VectorSource<
-    Feature<Point> | Feature<Polygon> | Feature<LineString> | Feature<MultiPolygon>
-  >;
+  vectorSource: VectorSource<Feature<Polygon> | Feature<LineString> | Feature<MultiPolygon>>;
 
   vectorLayer: VectorLayer<
-    VectorSource<Feature<Point> | Feature<Polygon> | Feature<LineString> | Feature<MultiPolygon>>
+    VectorSource<Feature<Polygon> | Feature<LineString> | Feature<MultiPolygon>>
   >;
 
   constructor({
@@ -107,7 +105,9 @@ export default class Layer {
     this.mapSize = mapSize;
     this.layerId = layerId;
 
-    this.vectorSource.addFeatures(this.getTextsFeatures());
+    const textsFeatures = this.getTextsFeatures();
+    this.vectorSource.addFeatures(textsFeatures);
+
     this.vectorSource.addFeatures(this.getRectsFeatures());
     this.vectorSource.addFeatures(this.getOvalsFeatures());
     const imagesFeatures = this.getImagesFeatures();
@@ -127,53 +127,39 @@ export default class Layer {
 
     this.vectorLayer.set('id', layerId);
     this.vectorLayer.set('imagesFeatures', imagesFeatures);
+    this.vectorLayer.set('textsFeatures', textsFeatures);
     this.vectorLayer.set('drawImage', this.drawImage.bind(this));
     this.vectorLayer.set('drawText', this.drawText.bind(this));
   }
 
-  private getTextsFeatures = (): Array<Feature<Point>> => {
-    const textObjects = Object.values(this.texts).map(text => {
-      return new Text({
-        x: text.x,
-        y: text.y,
-        zIndex: text.z,
-        width: text.width,
-        height: text.height,
-        layer: text.layer,
-        fontColor: text.color,
-        borderColor: text.borderColor,
-        fontSize: text.fontSize,
-        text: text.notes,
-        verticalAlign: text.verticalAlign as VerticalAlign,
-        horizontalAlign: text.horizontalAlign as HorizontalAlign,
-        pointToProjection: this.pointToProjection,
-        mapInstance: this.mapInstance,
-      });
-    });
-    return textObjects.map(text => text.feature);
+  private getTextsFeatures = (): Array<Feature<Polygon>> => {
+    return Object.values(this.texts).map(text => this.getTextFeature(text));
   };
 
-  private drawText(text: LayerText): void {
+  private drawText(text: LayerTextModel): void {
     const textFeature = this.getTextFeature(text);
     this.vectorSource.addFeature(textFeature);
   }
 
-  private getTextFeature(text: LayerText): Feature<Point> {
-    const textObject = new Text({
+  private getTextFeature(text: LayerTextModel): Feature<Polygon> {
+    const textObject = new LayerText({
+      elementId: text.id,
       x: text.x,
       y: text.y,
       zIndex: text.z,
       width: text.width,
       height: text.height,
       layer: text.layer,
-      fontColor: text.color,
+      color: text.color,
       borderColor: text.borderColor,
+      backgroundColor: text.backgroundColor,
       fontSize: text.fontSize,
       text: text.notes,
       verticalAlign: text.verticalAlign as VerticalAlign,
       horizontalAlign: text.horizontalAlign as HorizontalAlign,
       pointToProjection: this.pointToProjection,
       mapInstance: this.mapInstance,
+      mapSize: this.mapSize,
     });
     return textObject.feature;
   }
diff --git a/src/components/Map/MapViewer/utils/shapes/elements/Glyph/LayerImage.ts b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage.ts
similarity index 54%
rename from src/components/Map/MapViewer/utils/shapes/elements/Glyph/LayerImage.ts
rename to src/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage.ts
index ff893bdf860f74ce2a2d0c69e9aa6fce96400419..b7d306bb6f8f1456d337080ab1b9a3f4a5db62bc 100644
--- a/src/components/Map/MapViewer/utils/shapes/elements/Glyph/LayerImage.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage.ts
@@ -3,6 +3,11 @@ import { MapInstance } from '@/types/map';
 import { MapSize } from '@/redux/map/map.types';
 import { LayerImage as LayerImageModel } from '@/types/models';
 import Glyph from '@/components/Map/MapViewer/utils/shapes/elements/Glyph/Glyph';
+import { store } from '@/redux/store';
+import { updateLayerImageObject } from '@/redux/layers/layers.thunks';
+import { layerUpdateImage } from '@/redux/layers/layers.slice';
+import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
+import { BoundingBox } from '@/components/Map/MapViewer/MapViewer.types';
 
 export type LayerImageProps = {
   elementId: number;
@@ -47,11 +52,35 @@ export default class LayerImage extends Glyph {
       mapSize,
     });
     this.layer = layer;
-    this.feature.set('getGlyphData', this.getGlyphData.bind(this));
+    this.feature.set('getObjectData', this.getData.bind(this));
+    this.feature.set('save', this.save.bind(this));
     this.feature.set('layer', layer);
   }
 
-  private getGlyphData(): LayerImageModel {
+  private async save({
+    modelId,
+    boundingBox,
+  }: {
+    modelId: number;
+    boundingBox: BoundingBox;
+  }): Promise<void> {
+    const { dispatch } = store;
+    const layerImage = await dispatch(
+      updateLayerImageObject({
+        modelId,
+        layerId: this.layer,
+        ...this.getData(),
+        ...boundingBox,
+      }),
+    ).unwrap();
+    if (layerImage) {
+      dispatch(layerUpdateImage({ modelId, layerId: layerImage.layer, layerImage }));
+      dispatch(mapEditToolsSetLayerObject(layerImage));
+      this.updateElement(layerImage);
+    }
+  }
+
+  private getData(): LayerImageModel {
     return {
       id: this.elementId,
       x: this.x,
diff --git a/src/components/Map/MapViewer/utils/shapes/text/Text.test.ts b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.test.ts
similarity index 75%
rename from src/components/Map/MapViewer/utils/shapes/text/Text.test.ts
rename to src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.test.ts
index 2f2e145da280fd69de1abcadbef8d3e97c5ce839..7db76f34349d662a45cccf9d5d0e529e9ad22870 100644
--- a/src/components/Map/MapViewer/utils/shapes/text/Text.test.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.test.ts
@@ -3,17 +3,20 @@ import { Map } from 'ol';
 import { Style } from 'ol/style';
 import View from 'ol/View';
 import { BLACK_COLOR } from '@/components/Map/MapViewer/MapViewer.constants';
-import Text, { TextProps } from '@/components/Map/MapViewer/utils/shapes/text/Text';
+import LayerText, {
+  LayerTextProps,
+} from '@/components/Map/MapViewer/utils/shapes/layer/elements/LayerText';
 import getTextStyle from '@/components/Map/MapViewer/utils/shapes/text/getTextStyle';
 import { rgbToHex } from '@/components/Map/MapViewer/utils/shapes/style/rgbToHex';
 import getTextCoords from '@/components/Map/MapViewer/utils/shapes/text/getTextCoords';
+import { DEFAULT_TILE_SIZE } from '@/constants/map';
 
-jest.mock('./getTextCoords');
-jest.mock('./getTextStyle');
-jest.mock('../style/rgbToHex');
+jest.mock('../../text/getTextCoords');
+jest.mock('../../text/getTextStyle');
+jest.mock('../../style/rgbToHex');
 
 describe('Text', () => {
-  let props: TextProps;
+  let props: LayerTextProps;
 
   beforeEach(() => {
     const dummyElement = document.createElement('div');
@@ -26,6 +29,7 @@ describe('Text', () => {
       }),
     });
     props = {
+      elementId: 1,
       x: 0,
       y: 0,
       width: 100,
@@ -34,12 +38,20 @@ describe('Text', () => {
       layer: 1,
       text: 'Test',
       fontSize: 12,
-      fontColor: BLACK_COLOR,
+      color: BLACK_COLOR,
       borderColor: BLACK_COLOR,
+      backgroundColor: BLACK_COLOR,
       verticalAlign: 'MIDDLE',
       horizontalAlign: 'CENTER',
       pointToProjection: jest.fn(({ x, y }) => [x, y]),
       mapInstance,
+      mapSize: {
+        minZoom: 1,
+        maxZoom: 9,
+        width: 0,
+        height: 0,
+        tileSize: DEFAULT_TILE_SIZE,
+      },
     };
 
     (getTextStyle as jest.Mock).mockReturnValue(new Style());
@@ -48,7 +60,7 @@ describe('Text', () => {
   });
 
   it('should apply correct styles to the feature', () => {
-    const text = new Text(props);
+    const text = new LayerText(props);
     const { feature } = text;
 
     const style = feature.getStyleFunction()?.call(text, feature, 1);
@@ -61,7 +73,7 @@ describe('Text', () => {
   });
 
   it('should hide text when the scaled font size is too small', () => {
-    const text = new Text(props);
+    const text = new LayerText(props);
     const { feature } = text;
 
     const style = feature.getStyleFunction()?.call(text, feature, 20);
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.ts b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.ts
new file mode 100644
index 0000000000000000000000000000000000000000..133034cf4bf778c89f6d46b8d18a86f0a5473527
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.ts
@@ -0,0 +1,315 @@
+/* eslint-disable no-magic-numbers */
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import Style from 'ol/style/Style';
+import { Point } from 'ol/geom';
+import { Feature } from 'ol';
+import { FeatureLike } from 'ol/Feature';
+import { MapInstance } from '@/types/map';
+import { LayerText as LayerTextModel, Color } from '@/types/models';
+import { TEXT_CUTOFF_SCALE } from '@/components/Map/MapViewer/MapViewer.constants';
+import {
+  BoundingBox,
+  HorizontalAlign,
+  VerticalAlign,
+} from '@/components/Map/MapViewer/MapViewer.types';
+import getTextCoords from '@/components/Map/MapViewer/utils/shapes/text/getTextCoords';
+import getTextStyle from '@/components/Map/MapViewer/utils/shapes/text/getTextStyle';
+import { rgbToHex } from '@/components/Map/MapViewer/utils/shapes/style/rgbToHex';
+import Polygon from 'ol/geom/Polygon';
+import getStroke from '@/components/Map/MapViewer/utils/shapes/style/getStroke';
+import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
+import getScaledElementStyle from '@/components/Map/MapViewer/utils/shapes/style/getScaledElementStyle';
+import { Stroke } from 'ol/style';
+import { MapSize } from '@/redux/map/map.types';
+import getBoundingBoxFromExtent from '@/components/Map/MapViewer/utils/shapes/coords/getBoundingBoxFromExtent';
+import { Coordinate } from 'ol/coordinate';
+import { store } from '@/redux/store';
+import { updateLayerText } from '@/redux/layers/layers.thunks';
+import { layerUpdateText } from '@/redux/layers/layers.slice';
+import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
+
+export interface LayerTextProps {
+  elementId: number;
+  x: number;
+  y: number;
+  width: number;
+  height: number;
+  layer: number;
+  zIndex: number;
+  text: string;
+  fontSize: number;
+  color: Color;
+  borderColor: Color;
+  backgroundColor: Color;
+  verticalAlign: VerticalAlign;
+  horizontalAlign: HorizontalAlign;
+  pointToProjection: UsePointToProjectionResult;
+  mapInstance: MapInstance;
+  mapSize: MapSize;
+}
+
+export default class LayerText {
+  elementId: number;
+
+  x: number;
+
+  y: number;
+
+  zIndex: number;
+
+  width: number;
+
+  height: number;
+
+  layer: number;
+
+  text: string;
+
+  verticalAlign: VerticalAlign;
+
+  horizontalAlign: HorizontalAlign;
+
+  backgroundColor: Color;
+
+  borderColor: Color;
+
+  color: Color;
+
+  fontSize: number;
+
+  style: Style;
+
+  polygonStyle: Style;
+
+  polygon: Polygon = new Polygon([]);
+
+  strokeStyle: Stroke;
+
+  point: Point;
+
+  feature: Feature<Polygon>;
+
+  mapSize: MapSize;
+
+  pointToProjection: UsePointToProjectionResult;
+
+  constructor({
+    elementId,
+    x,
+    y,
+    width,
+    height,
+    layer,
+    zIndex,
+    text,
+    fontSize,
+    color,
+    borderColor,
+    backgroundColor,
+    verticalAlign,
+    horizontalAlign,
+    pointToProjection,
+    mapInstance,
+    mapSize,
+  }: LayerTextProps) {
+    this.text = text;
+    this.fontSize = fontSize;
+    this.elementId = elementId;
+    this.x = x;
+    this.y = y;
+    this.zIndex = zIndex;
+    this.width = width;
+    this.height = height;
+    this.layer = layer;
+    this.text = text;
+    this.verticalAlign = verticalAlign;
+    this.horizontalAlign = horizontalAlign;
+    this.backgroundColor = backgroundColor;
+    this.borderColor = borderColor;
+    this.color = color;
+    this.mapSize = mapSize;
+    this.pointToProjection = pointToProjection;
+
+    const textCoords = getTextCoords({
+      x,
+      y,
+      height,
+      width,
+      fontSize,
+      verticalAlign,
+      horizontalAlign,
+      pointToProjection,
+    });
+    this.drawPolygon();
+    this.strokeStyle = getStroke({
+      color: rgbToHex(borderColor),
+      width: 1,
+    });
+    this.polygonStyle = getStyle({
+      geometry: this.polygon,
+      borderColor,
+      fillColor: { rgb: 0, alpha: 0 },
+      lineWidth: 1,
+      zIndex,
+    });
+
+    const textStyle = getTextStyle({
+      text,
+      fontSize,
+      color: rgbToHex(color),
+      zIndex,
+      horizontalAlign,
+    });
+    this.point = new Point(textCoords);
+    this.style = textStyle;
+    this.style.setGeometry(this.point);
+
+    this.feature = new Feature({
+      geometry: this.polygon,
+      getScale: (resolution: number): number => {
+        const maxZoom = mapInstance?.getView().get('originalMaxZoom');
+        if (maxZoom) {
+          const minResolution = mapInstance?.getView().getResolutionForZoom(maxZoom);
+          if (minResolution) {
+            return Math.round((minResolution / resolution) * 100) / 100;
+          }
+        }
+        return 1;
+      },
+      layer,
+    });
+    this.feature.setId(this.elementId);
+    this.feature.set('getObjectData', this.getData.bind(this));
+    this.feature.set('setCoordinates', this.setCoordinates.bind(this));
+    this.feature.set('refreshPolygon', this.refreshPolygon.bind(this));
+    this.feature.set('save', this.save.bind(this));
+    this.feature.set('updateElement', this.updateElement.bind(this));
+    this.feature.setStyle(this.getStyle.bind(this));
+  }
+
+  private getData(): LayerTextModel {
+    return {
+      id: this.elementId,
+      x: this.x,
+      y: this.y,
+      z: this.zIndex,
+      width: this.width,
+      height: this.height,
+      layer: this.layer,
+      fontSize: this.fontSize,
+      notes: this.text,
+      verticalAlign: this.verticalAlign,
+      horizontalAlign: this.horizontalAlign,
+      backgroundColor: this.backgroundColor,
+      borderColor: this.borderColor,
+      color: this.color,
+    };
+  }
+
+  private drawPolygon(): void {
+    this.polygon = new Polygon([
+      [
+        this.pointToProjection({ x: this.x, y: this.y }),
+        this.pointToProjection({ x: this.x + this.width, y: this.y }),
+        this.pointToProjection({ x: this.x + this.width, y: this.y + this.height }),
+        this.pointToProjection({ x: this.x, y: this.y + this.height }),
+        this.pointToProjection({ x: this.x, y: this.y }),
+      ],
+    ]);
+  }
+
+  private async save({
+    modelId,
+    boundingBox,
+  }: {
+    modelId: number;
+    boundingBox: BoundingBox;
+  }): Promise<void> {
+    const { dispatch } = store;
+    const layerText = await dispatch(
+      updateLayerText({
+        modelId,
+        layerId: this.layer,
+        ...this.getData(),
+        ...boundingBox,
+      }),
+    ).unwrap();
+    if (layerText) {
+      dispatch(layerUpdateText({ modelId, layerId: layerText.layer, layerText }));
+      dispatch(mapEditToolsSetLayerObject(layerText));
+      this.updateElement(layerText);
+    }
+  }
+
+  private refreshPolygon(): void {
+    this.drawPolygon();
+    this.polygonStyle.setGeometry(this.polygon);
+    this.feature.setGeometry(this.polygon);
+    this.feature.changed();
+  }
+
+  private refreshZIndex(): void {
+    this.polygonStyle.setZIndex(this.zIndex);
+    this.style.setZIndex(this.zIndex);
+    this.feature.changed();
+  }
+
+  private updateElement(layerText: LayerTextModel): void {
+    this.elementId = layerText.id;
+    this.x = layerText.x;
+    this.y = layerText.y;
+    this.zIndex = layerText.z;
+    this.width = layerText.width;
+    this.height = layerText.height;
+    this.text = layerText.notes;
+    this.fontSize = layerText.fontSize;
+    this.color = layerText.color;
+    this.borderColor = layerText.borderColor;
+    this.verticalAlign = layerText.verticalAlign;
+    this.horizontalAlign = layerText.horizontalAlign;
+
+    this.refreshPolygon();
+    this.refreshZIndex();
+    this.feature.changed();
+  }
+
+  private setCoordinates(coords: Coordinate[][]): void {
+    const geometry = this.polygonStyle.getGeometry();
+    if (geometry && geometry instanceof Polygon) {
+      geometry.setCoordinates(coords);
+    }
+  }
+
+  protected getStyle(feature: FeatureLike, resolution: number): Style | Array<Style> | void {
+    const getScale = feature.get('getScale');
+    let scale = 1;
+    if (getScale instanceof Function) {
+      scale = getScale(resolution);
+    }
+    const geometry = feature.getGeometry();
+    if (geometry && geometry instanceof Polygon) {
+      const polygonExtent = geometry.getExtent();
+      if (polygonExtent) {
+        const boundingBox = getBoundingBoxFromExtent(polygonExtent, this.mapSize);
+        const textCoords = getTextCoords({
+          x: boundingBox.x,
+          y: boundingBox.y,
+          height: boundingBox.height,
+          width: boundingBox.width,
+          fontSize: this.fontSize,
+          verticalAlign: this.verticalAlign,
+          horizontalAlign: this.horizontalAlign,
+          pointToProjection: this.pointToProjection,
+        });
+        this.point.setCoordinates(textCoords);
+      }
+    }
+    if (scale < TEXT_CUTOFF_SCALE) {
+      return undefined;
+    }
+    return [
+      getScaledElementStyle(this.polygonStyle, this.strokeStyle, scale),
+      getScaledElementStyle(this.style, undefined, scale),
+    ];
+  }
+}
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformImageInteraction.test.ts b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.test.ts
similarity index 85%
rename from src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformImageInteraction.test.ts
rename to src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.test.ts
index c2f77a2985e3e4a4e7bcf3b10c4add2ba9085751..1cb1fec97800d98c08ca67e1467c3da685d0cded 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformImageInteraction.test.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.test.ts
@@ -10,13 +10,13 @@ import { DEFAULT_TILE_SIZE } from '@/constants/map';
 import { Collection, Feature } from 'ol';
 import Transform from 'ol-ext/interaction/Transform';
 import { Geometry } from 'ol/geom';
-import getTransformImageInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformImageInteraction';
+import getTransformInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction';
 
 jest.mock('../../../../../../../utils/map/latLngToPoint', () => ({
   latLngToPoint: jest.fn(latLng => ({ x: latLng[0], y: latLng[1] })),
 }));
 
-describe('getTransformImageInteraction', () => {
+describe('getTransformInteraction', () => {
   let store = {} as ToolkitStoreWithSingleSlice<ModalState>;
   let modelIdMock: number;
   let featuresCollectionMock: Collection<Feature<Geometry>>;
@@ -39,7 +39,7 @@ describe('getTransformImageInteraction', () => {
   });
 
   it('returns a Transform interaction', () => {
-    const transformInteraction = getTransformImageInteraction(
+    const transformInteraction = getTransformInteraction(
       store.dispatch,
       mapSize,
       modelIdMock,
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformImageInteraction.ts b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.ts
similarity index 76%
rename from src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformImageInteraction.ts
rename to src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.ts
index 3a1435fd1a8db4b9dc6b2d9d669f9ddc799e0412..c1c8565c2fedda6278186bda9ec2a28c5996105f 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformImageInteraction.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.ts
@@ -5,15 +5,13 @@ import Transform from 'ol-ext/interaction/Transform';
 import { Geometry } from 'ol/geom';
 import { Collection, Feature } from 'ol';
 import BaseEvent from 'ol/events/Event';
-import { updateLayerImageObject } from '@/redux/layers/layers.thunks';
-import { layerUpdateImage } from '@/redux/layers/layers.slice';
 import getBoundingBoxFromExtent from '@/components/Map/MapViewer/utils/shapes/coords/getBoundingBoxFromExtent';
 import { MapSize } from '@/redux/map/map.types';
 import { Extent } from 'ol/extent';
 import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
 import { openDrawer } from '@/redux/drawer/drawer.slice';
 
-export default function getTransformImageInteraction(
+export default function getTransformInteraction(
   dispatch: AppDispatch,
   mapSize: MapSize,
   modelId: number,
@@ -86,6 +84,11 @@ export default function getTransformImageInteraction(
       newGeometry.scale(1, -1);
       feature.setGeometry(newGeometry);
       transform.setSelection(new Collection([feature]));
+      return;
+    }
+    const setCoordinates = feature.get('setCoordinates');
+    if (geometry instanceof Polygon && setCoordinates instanceof Function) {
+      setCoordinates(geometry.getCoordinates());
     }
   });
 
@@ -96,10 +99,10 @@ export default function getTransformImageInteraction(
       dispatch(mapEditToolsSetLayerObject(null));
       return;
     }
-    const getGlyphData = features.item(0).get('getGlyphData');
-    if (getGlyphData && getGlyphData instanceof Function) {
-      const glyphData = getGlyphData();
-      dispatch(mapEditToolsSetLayerObject(glyphData));
+    const getObjectData = features.item(0).get('getObjectData');
+    if (getObjectData && getObjectData instanceof Function) {
+      const objectData = getObjectData();
+      dispatch(mapEditToolsSetLayerObject(objectData));
       dispatch(openDrawer('layers'));
     }
   });
@@ -107,30 +110,13 @@ export default function getTransformImageInteraction(
   transform.on(['scaleend', 'translateend'], async (event: BaseEvent | Event): Promise<void> => {
     const transformEvent = event as unknown as { feature: Feature };
     const { feature } = transformEvent;
-    const setCoordinates = feature.get('setCoordinates');
-    const getGlyphData = feature.get('getGlyphData');
     const refreshPolygon = feature.get('refreshPolygon');
+    const save = feature.get('save');
     const geometry = feature.getGeometry();
-    if (geometry && getGlyphData instanceof Function) {
-      const glyphData = getGlyphData();
+    if (geometry && save instanceof Function) {
       try {
         const boundingBox = getBoundingBoxFromExtent(geometry.getExtent(), mapSize);
-        const layerImage = await dispatch(
-          updateLayerImageObject({
-            modelId,
-            layerId: glyphData.layer,
-            ...glyphData,
-            ...boundingBox,
-          }),
-        ).unwrap();
-        if (layerImage) {
-          dispatch(layerUpdateImage({ modelId, layerId: layerImage.layer, layerImage }));
-          dispatch(mapEditToolsSetLayerObject(layerImage));
-        }
-        if (geometry instanceof Polygon && setCoordinates instanceof Function) {
-          setCoordinates(geometry.getCoordinates());
-          geometry.changed();
-        }
+        save({ modelId, boundingBox });
       } catch {
         if (refreshPolygon instanceof Function) {
           refreshPolygon();
diff --git a/src/components/Map/MapViewer/utils/shapes/elements/Glyph/updateGlyph.ts b/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts
similarity index 60%
rename from src/components/Map/MapViewer/utils/shapes/elements/Glyph/updateGlyph.ts
rename to src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts
index 054189738b3ace4ef4fb68d64a3113500496ce43..88f50d44622b43bebd15476b09d4543ee634143e 100644
--- a/src/components/Map/MapViewer/utils/shapes/elements/Glyph/updateGlyph.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts
@@ -1,20 +1,20 @@
 import VectorSource from 'ol/source/Vector';
-import { LayerImage } from '@/types/models';
+import { LayerImage, LayerText } from '@/types/models';
 import { MapInstance } from '@/types/map';
 
-export default function updateGlyph(
+export default function updateElement(
   mapInstance: MapInstance,
   layerId: number,
-  layerImage: LayerImage,
+  layerObject: LayerImage | LayerText,
 ): void {
   mapInstance?.getAllLayers().forEach(layer => {
     if (layer.get('id') === layerId) {
       const source = layer.getSource();
       if (source instanceof VectorSource) {
-        const feature = source.getFeatureById(layerImage.id);
-        const update = feature?.get('update');
+        const feature = source.getFeatureById(layerObject.id);
+        const update = feature?.get('updateElement');
         if (update && update instanceof Function) {
-          update(layerImage);
+          update(layerObject);
           feature.changed();
         }
       }
diff --git a/src/components/Map/MapViewer/utils/shapes/text/Text.ts b/src/components/Map/MapViewer/utils/shapes/text/Text.ts
deleted file mode 100644
index c1bc5799c7d386b1abde85d309bdfde5254ebc62..0000000000000000000000000000000000000000
--- a/src/components/Map/MapViewer/utils/shapes/text/Text.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-/* eslint-disable no-magic-numbers */
-import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
-import Style from 'ol/style/Style';
-import { Point } from 'ol/geom';
-import { Feature } from 'ol';
-import { FeatureLike } from 'ol/Feature';
-import { MapInstance } from '@/types/map';
-import { Color } from '@/types/models';
-import { TEXT_CUTOFF_SCALE } from '@/components/Map/MapViewer/MapViewer.constants';
-import { HorizontalAlign, VerticalAlign } from '@/components/Map/MapViewer/MapViewer.types';
-import getTextCoords from '@/components/Map/MapViewer/utils/shapes/text/getTextCoords';
-import getTextStyle from '@/components/Map/MapViewer/utils/shapes/text/getTextStyle';
-import { rgbToHex } from '@/components/Map/MapViewer/utils/shapes/style/rgbToHex';
-import Polygon from 'ol/geom/Polygon';
-import getStroke from '@/components/Map/MapViewer/utils/shapes/style/getStroke';
-import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
-import getScaledElementStyle from '@/components/Map/MapViewer/utils/shapes/style/getScaledElementStyle';
-import { Stroke } from 'ol/style';
-
-export interface TextProps {
-  x: number;
-  y: number;
-  width: number;
-  height: number;
-  layer: number;
-  zIndex: number;
-  text: string;
-  fontSize: number;
-  fontColor: Color;
-  borderColor: Color;
-  verticalAlign: VerticalAlign;
-  horizontalAlign: HorizontalAlign;
-  pointToProjection: UsePointToProjectionResult;
-  mapInstance: MapInstance;
-}
-
-export default class Text {
-  text: string;
-
-  fontSize: number;
-
-  style: Style;
-
-  polygonStyle: Style;
-
-  strokeStyle: Stroke;
-
-  point: Point;
-
-  feature: Feature<Point>;
-
-  constructor({
-    x,
-    y,
-    width,
-    height,
-    layer,
-    zIndex,
-    text,
-    fontSize,
-    fontColor,
-    borderColor,
-    verticalAlign,
-    horizontalAlign,
-    pointToProjection,
-    mapInstance,
-  }: TextProps) {
-    this.text = text;
-    this.fontSize = fontSize;
-
-    const textCoords = getTextCoords({
-      x,
-      y,
-      height,
-      width,
-      fontSize,
-      verticalAlign,
-      horizontalAlign,
-      pointToProjection,
-    });
-    const borderPolygon = new Polygon([
-      [
-        pointToProjection({ x, y }),
-        pointToProjection({ x: x + width, y }),
-        pointToProjection({ x: x + width, y: y + height }),
-        pointToProjection({ x, y: y + height }),
-        pointToProjection({ x, y }),
-      ],
-    ]);
-    this.strokeStyle = getStroke({
-      color: rgbToHex(borderColor),
-      width: 1,
-    });
-    this.polygonStyle = getStyle({
-      geometry: borderPolygon,
-      borderColor,
-      fillColor: { rgb: 0, alpha: 0 },
-      lineWidth: 1,
-      zIndex,
-    });
-
-    const textStyle = getTextStyle({
-      text,
-      fontSize,
-      color: rgbToHex(fontColor),
-      zIndex,
-      horizontalAlign,
-    });
-    this.point = new Point(textCoords);
-    this.style = textStyle;
-    this.style.setGeometry(this.point);
-
-    this.feature = new Feature({
-      geometry: this.point,
-      getScale: (resolution: number): number => {
-        const maxZoom = mapInstance?.getView().get('originalMaxZoom');
-        if (maxZoom) {
-          const minResolution = mapInstance?.getView().getResolutionForZoom(maxZoom);
-          if (minResolution) {
-            return Math.round((minResolution / resolution) * 100) / 100;
-          }
-        }
-        return 1;
-      },
-      layer,
-    });
-
-    this.feature.setStyle(this.getStyle.bind(this));
-  }
-
-  protected getStyle(feature: FeatureLike, resolution: number): Style | Array<Style> | void {
-    const getScale = feature.get('getScale');
-    let scale = 1;
-    if (getScale instanceof Function) {
-      scale = getScale(resolution);
-    }
-    if (scale < TEXT_CUTOFF_SCALE) {
-      return undefined;
-    }
-    return [
-      getScaledElementStyle(this.polygonStyle, this.strokeStyle, scale),
-      getScaledElementStyle(this.style, undefined, scale),
-    ];
-  }
-}
diff --git a/src/components/Map/MapViewer/utils/shapes/text/getTextCoords.ts b/src/components/Map/MapViewer/utils/shapes/text/getTextCoords.ts
index e3224fc9f5272d288c53b55a82f0656f81f09a64..26acfb6b179599a520f69bd5b570e5444fd0ad6d 100644
--- a/src/components/Map/MapViewer/utils/shapes/text/getTextCoords.ts
+++ b/src/components/Map/MapViewer/utils/shapes/text/getTextCoords.ts
@@ -12,6 +12,7 @@ export default function getTextCoords({
   verticalAlign,
   horizontalAlign,
   pointToProjection,
+  useProjection = true,
 }: {
   x: number;
   y: number;
@@ -20,7 +21,8 @@ export default function getTextCoords({
   fontSize: number;
   verticalAlign: VerticalAlign;
   horizontalAlign: HorizontalAlign;
-  pointToProjection: UsePointToProjectionResult;
+  pointToProjection?: UsePointToProjectionResult;
+  useProjection?: boolean;
 }): Coordinate {
   const minX = x;
   const maxX = x + width;
@@ -41,5 +43,8 @@ export default function getTextCoords({
     textX = maxX;
   }
 
-  return pointToProjection({ x: textX, y: textY });
+  if (useProjection && pointToProjection) {
+    return pointToProjection({ x: textX, y: textY });
+  }
+  return [textX, textY];
 }
diff --git a/src/components/Map/MapViewer/utils/websocket/processLayerImage.ts b/src/components/Map/MapViewer/utils/websocket/processLayerImage.ts
index 84018d80755cc437d318b11683ae4ac5815aa7ed..6fd6ec3a4000b3d439178eb8a10a001dc5d86e65 100644
--- a/src/components/Map/MapViewer/utils/websocket/processLayerImage.ts
+++ b/src/components/Map/MapViewer/utils/websocket/processLayerImage.ts
@@ -2,7 +2,7 @@ import { WebSocketEntityUpdateInterface } from '@/utils/websocket-entity-updates
 import { store } from '@/redux/store';
 import { ENTITY_OPERATION_TYPES } from '@/utils/websocket-entity-updates/webSocketEntityUpdates.constants';
 import { getLayerImage } from '@/redux/layers/layers.thunks';
-import updateGlyph from '@/components/Map/MapViewer/utils/shapes/elements/Glyph/updateGlyph';
+import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement';
 import { MapInstance } from '@/types/map';
 import drawElementOnLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer';
 import { layerDeleteImage } from '@/redux/layers/layers.slice';
@@ -38,7 +38,7 @@ export default async function processLayerImage({
         drawFunctionKey: 'drawImage',
       });
     } else {
-      updateGlyph(mapInstance, data.layerId, resultImage);
+      updateElement(mapInstance, data.layerId, resultImage);
     }
   } else if (data.type === ENTITY_OPERATION_TYPES.ENTITY_DELETED) {
     dispatch(
diff --git a/src/components/Map/MapViewer/utils/websocket/processLayerText.ts b/src/components/Map/MapViewer/utils/websocket/processLayerText.ts
index f31697c4ea5ebbb4e8337d7df876bbb04fbf8bdc..e1740c979958dd74f31ef3c13cf8a96b562bc9ba 100644
--- a/src/components/Map/MapViewer/utils/websocket/processLayerText.ts
+++ b/src/components/Map/MapViewer/utils/websocket/processLayerText.ts
@@ -4,6 +4,9 @@ import { ENTITY_OPERATION_TYPES } from '@/utils/websocket-entity-updates/webSock
 import { getLayerText } from '@/redux/layers/layers.thunks';
 import { MapInstance } from '@/types/map';
 import drawElementOnLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer';
+import { layerDeleteText } from '@/redux/layers/layers.slice';
+import removeElementFromLayer from '@/components/Map/MapViewer/utils/shapes/elements/removeElementFromLayer';
+import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement';
 
 export default async function processLayerText({
   data,
@@ -13,7 +16,10 @@ export default async function processLayerText({
   mapInstance: MapInstance;
 }): Promise<void> {
   const { dispatch } = store;
-  if (data.type === ENTITY_OPERATION_TYPES.ENTITY_CREATED) {
+  if (
+    data.type === ENTITY_OPERATION_TYPES.ENTITY_CREATED ||
+    data.type === ENTITY_OPERATION_TYPES.ENTITY_UPDATED
+  ) {
     const resultText = await dispatch(
       getLayerText({
         modelId: data.mapId,
@@ -24,11 +30,24 @@ export default async function processLayerText({
     if (!resultText) {
       return;
     }
-    drawElementOnLayer({
-      mapInstance,
-      activeLayer: data.layerId,
-      object: resultText,
-      drawFunctionKey: 'drawText',
-    });
+    if (data.type === ENTITY_OPERATION_TYPES.ENTITY_CREATED) {
+      drawElementOnLayer({
+        mapInstance,
+        activeLayer: data.layerId,
+        object: resultText,
+        drawFunctionKey: 'drawText',
+      });
+    } else {
+      updateElement(mapInstance, data.layerId, resultText);
+    }
+  } else if (data.type === ENTITY_OPERATION_TYPES.ENTITY_DELETED) {
+    dispatch(
+      layerDeleteText({
+        modelId: data.mapId,
+        layerId: data.layerId,
+        textId: data.entityId,
+      }),
+    );
+    removeElementFromLayer({ mapInstance, layerId: data.layerId, featureId: data.entityId });
   }
 }
diff --git a/src/models/layerTextSchema.ts b/src/models/layerTextSchema.ts
index 0ec90665b7532e11a8e2782cf28c9e9ef3164fe4..a575b1390ef46ba1b67509f90b0ba9a48a5eefee 100644
--- a/src/models/layerTextSchema.ts
+++ b/src/models/layerTextSchema.ts
@@ -11,8 +11,8 @@ export const layerTextSchema = z.object({
   layer: z.number(),
   fontSize: z.number(),
   notes: z.string(),
-  verticalAlign: z.string(),
-  horizontalAlign: z.string(),
+  verticalAlign: z.enum(['TOP', 'MIDDLE', 'BOTTOM']),
+  horizontalAlign: z.enum(['LEFT', 'RIGHT', 'CENTER', 'END', 'START']),
   backgroundColor: colorSchema,
   borderColor: colorSchema,
   color: colorSchema,
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index 9eb33c02a449c4d869e659f88bcfe8e9522e53b0..18186d6f706cc1a2db43a31d0d30990c871fa4b0 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -64,6 +64,10 @@ export const apiPath = {
     `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/texts/`,
   getLayerText: (modelId: number, layerId: number, imageId: number | string): string =>
     `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/texts/${imageId}`,
+  updateLayerText: (modelId: number, layerId: number, textId: number | string): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/texts/${textId}`,
+  removeLayerText: (modelId: number, layerId: number, textId: number | string): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/texts/${textId}`,
   getLayer: (modelId: number, layerId: number): string =>
     `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}`,
   getGlyphImage: (glyphId: number): string =>
diff --git a/src/redux/layers/layers.reducers.ts b/src/redux/layers/layers.reducers.ts
index 0213d7145366de6126d4855bab3665d5de0c3c66..238a3441a2e05c7f6d21a499a10985bbe7eed09e 100644
--- a/src/redux/layers/layers.reducers.ts
+++ b/src/redux/layers/layers.reducers.ts
@@ -198,3 +198,35 @@ export const layerAddTextReducer = (
   }
   layer.texts[layerText.id] = layerText;
 };
+
+export const layerUpdateTextReducer = (
+  state: LayersState,
+  action: PayloadAction<{ modelId: number; layerId: number; layerText: LayerText }>,
+): void => {
+  const { modelId, layerId, layerText } = action.payload;
+  const { data } = state[modelId];
+  if (!data) {
+    return;
+  }
+  const layer = data.layers.find(layerState => layerState.details.id === layerId);
+  if (!layer) {
+    return;
+  }
+  layer.texts[layerText.id] = layerText;
+};
+
+export const layerDeleteTextReducer = (
+  state: LayersState,
+  action: PayloadAction<{ modelId: number; layerId: number; textId: number }>,
+): void => {
+  const { modelId, layerId, textId } = action.payload;
+  const { data } = state[modelId];
+  if (!data) {
+    return;
+  }
+  const layer = data.layers.find(layerState => layerState.details.id === layerId);
+  if (!layer) {
+    return;
+  }
+  delete layer.texts[textId];
+};
diff --git a/src/redux/layers/layers.slice.ts b/src/redux/layers/layers.slice.ts
index dcd20ceba8302ea711ac5f583abffbf65e051dac..871012fcfb77c30fee1490cf6e1c50aaee65d624 100644
--- a/src/redux/layers/layers.slice.ts
+++ b/src/redux/layers/layers.slice.ts
@@ -12,6 +12,8 @@ import {
   setDrawLayerReducer,
   setLayerToInactiveReducer,
   setLayerToActiveReducer,
+  layerDeleteTextReducer,
+  layerUpdateTextReducer,
 } from '@/redux/layers/layers.reducers';
 
 export const layersSlice = createSlice({
@@ -25,6 +27,8 @@ export const layersSlice = createSlice({
     layerUpdateImage: layerUpdateImageReducer,
     layerDeleteImage: layerDeleteImageReducer,
     layerAddText: layerAddTextReducer,
+    layerUpdateText: layerUpdateTextReducer,
+    layerDeleteText: layerDeleteTextReducer,
     setDrawLayer: setDrawLayerReducer,
   },
   extraReducers: builder => {
@@ -42,6 +46,8 @@ export const {
   layerUpdateImage,
   layerDeleteImage,
   layerAddText,
+  layerUpdateText,
+  layerDeleteText,
   setDrawLayer,
 } = layersSlice.actions;
 
diff --git a/src/redux/layers/layers.thunks.ts b/src/redux/layers/layers.thunks.ts
index 847d84d22a8a47c26f12b1d3be6beea86e0c3ab3..66035fd8362c4d412df45932263d47761a022a55 100644
--- a/src/redux/layers/layers.thunks.ts
+++ b/src/redux/layers/layers.thunks.ts
@@ -1,7 +1,7 @@
 /* eslint-disable no-magic-numbers */
 import { z as zod } from 'zod';
 import { apiPath } from '@/redux/apiPath';
-import { Layer, LayerImage, Layers, LayerText } from '@/types/models';
+import { Color, Layer, LayerImage, Layers, LayerText } from '@/types/models';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
 import { createAsyncThunk } from '@reduxjs/toolkit';
 import { ThunkConfig } from '@/types/store';
@@ -22,7 +22,11 @@ import { layerLineSchema } from '@/models/layerLineSchema';
 import { layerImageSchema } from '@/models/layerImageSchema';
 import arrayToKeyValue from '@/utils/array/arrayToKeyValue';
 import { LayerTextFactoryForm } from '@/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactory.types';
-import { BoundingBox } from '@/components/Map/MapViewer/MapViewer.types';
+import {
+  BoundingBox,
+  HorizontalAlign,
+  VerticalAlign,
+} from '@/components/Map/MapViewer/MapViewer.types';
 
 export const getLayer = createAsyncThunk<
   Layer | null,
@@ -307,3 +311,81 @@ export const getLayerText = createAsyncThunk<
     return Promise.reject(getError({ error }));
   }
 });
+
+export const removeLayerText = createAsyncThunk<
+  null,
+  { modelId: number; layerId: number; textId: number },
+  ThunkConfig
+>('layers/removeLayerText', async ({ modelId, layerId, textId }) => {
+  try {
+    await axiosInstanceNewAPI.delete<void>(apiPath.removeLayerText(modelId, layerId, textId));
+    return null;
+  } catch (error) {
+    return Promise.reject(getError({ error }));
+  }
+});
+
+export const updateLayerText = createAsyncThunk<
+  LayerText | null,
+  {
+    modelId: number;
+    layerId: number;
+    id: number;
+    x: number;
+    y: number;
+    z: number;
+    width: number;
+    height: number;
+    fontSize: number;
+    notes: string;
+    verticalAlign: VerticalAlign;
+    horizontalAlign: HorizontalAlign;
+    color: Color;
+    borderColor: Color;
+  },
+  ThunkConfig
+>(
+  'layers/updateLayerText',
+  async ({
+    modelId,
+    layerId,
+    id,
+    x,
+    y,
+    z,
+    width,
+    height,
+    fontSize,
+    notes,
+    verticalAlign,
+    horizontalAlign,
+    color,
+    borderColor,
+  }) => {
+    try {
+      const { data } = await axiosInstanceNewAPI.put<LayerText>(
+        apiPath.updateLayerText(modelId, layerId, id),
+        {
+          x,
+          y,
+          z,
+          width,
+          height,
+          fontSize,
+          notes,
+          verticalAlign,
+          horizontalAlign,
+          color,
+          borderColor,
+        },
+      );
+      const isDataValid = validateDataUsingZodSchema(data, layerTextSchema);
+      if (isDataValid) {
+        return data;
+      }
+      return null;
+    } catch (error) {
+      return Promise.reject(getError({ error }));
+    }
+  },
+);
diff --git a/src/redux/mapEditTools/mapEditTools.mock.ts b/src/redux/mapEditTools/mapEditTools.mock.ts
index d6fe529ca573712859930af2879cf0591ddb7b50..fbbacec71b385a8f9ee7060ddce4c290a1ba4cd0 100644
--- a/src/redux/mapEditTools/mapEditTools.mock.ts
+++ b/src/redux/mapEditTools/mapEditTools.mock.ts
@@ -2,5 +2,5 @@ import { MapEditToolsState } from '@/redux/mapEditTools/mapEditTools.types';
 
 export const MAP_EDIT_TOOLS_STATE_INITIAL_MOCK: MapEditToolsState = {
   activeAction: null,
-  layerImageObject: null,
+  layerObject: null,
 };
diff --git a/src/redux/mapEditTools/mapEditTools.reducers.ts b/src/redux/mapEditTools/mapEditTools.reducers.ts
index da3f5f7f7d57126be4f93d49166881a093f58a47..d45e719f8a892cd828dc650ae0d03ea9dfb808e7 100644
--- a/src/redux/mapEditTools/mapEditTools.reducers.ts
+++ b/src/redux/mapEditTools/mapEditTools.reducers.ts
@@ -2,7 +2,7 @@
 import { PayloadAction } from '@reduxjs/toolkit';
 import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants';
 import { MapEditToolsState } from '@/redux/mapEditTools/mapEditTools.types';
-import { LayerImage } from '@/types/models';
+import { LayerImage, LayerText } from '@/types/models';
 
 export const mapEditToolsSetActiveActionReducer = (
   state: MapEditToolsState,
@@ -13,7 +13,7 @@ export const mapEditToolsSetActiveActionReducer = (
 
 export const mapEditToolsSetLayerObjectReducer = (
   state: MapEditToolsState,
-  action: PayloadAction<LayerImage | null>,
+  action: PayloadAction<LayerImage | LayerText | null>,
 ): void => {
-  state.layerImageObject = action.payload;
+  state.layerObject = action.payload;
 };
diff --git a/src/redux/mapEditTools/mapEditTools.selectors.ts b/src/redux/mapEditTools/mapEditTools.selectors.ts
index 2b29bd35c204f8f06d6459d2fb7c89429e53a82a..d3ea7d128e91a479e9cdbf8311d0d7892da37a84 100644
--- a/src/redux/mapEditTools/mapEditTools.selectors.ts
+++ b/src/redux/mapEditTools/mapEditTools.selectors.ts
@@ -9,9 +9,9 @@ export const mapEditToolsActiveActionSelector = createSelector(
   state => state.activeAction,
 );
 
-export const mapEditToolsLayerImageObjectSelector = createSelector(
+export const mapEditToolsLayerObjectSelector = createSelector(
   mapEditToolsSelector,
-  state => state.layerImageObject,
+  state => state.layerObject,
 );
 
 export const isMapEditToolsActiveSelector = createSelector(mapEditToolsSelector, state =>
diff --git a/src/redux/mapEditTools/mapEditTools.types.ts b/src/redux/mapEditTools/mapEditTools.types.ts
index e141e6b86f35356c891bf47320a1784b945ee525..4c216c406c2b890a4fbc6fe97701928f0f751828 100644
--- a/src/redux/mapEditTools/mapEditTools.types.ts
+++ b/src/redux/mapEditTools/mapEditTools.types.ts
@@ -1,7 +1,7 @@
 import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants';
-import { LayerImage } from '@/types/models';
+import { LayerImage, LayerText } from '@/types/models';
 
 export type MapEditToolsState = {
   activeAction: keyof typeof MAP_EDIT_ACTIONS | null;
-  layerImageObject: LayerImage | null;
+  layerObject: LayerImage | LayerText | null;
 };