diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index f57c4495afa1b867a1ba1c89ad19709ea27a6fab..1f4abdd8edd593b08e514911f328afe2038f9c58 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -501,7 +501,7 @@ void LLControlAvatar::getAnimatedVolumes(std::vector<LLVOVolume*>& volumes)
 		 iter != child_list.end(); ++iter)
 	{
 		LLViewerObject* childp = *iter;
-        LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp);
+        LLVOVolume *child_volp = childp ? childp->asVolume() : nullptr;
         if (child_volp && child_volp->isAnimatedObject())
         {
             volumes.push_back(child_volp);
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 0429749e11dc0659a124006dfcac81c268ba54f2..96acc5b4249ad819589c0aa870f4fec1c32c6b46 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -1251,8 +1251,8 @@ void LLFloaterTools::getMediaState()
 		for ( ; iter != end; ++iter)
 		{
 			LLSelectNode* node = *iter;
-			LLVOVolume* object = dynamic_cast<LLVOVolume*>(node->getObject());
-			if (NULL != object)
+			LLVOVolume* object = node ? node->getObject()->asVolume() : nullptr;
+			if (nullptr != object)
 			{
 				if (!object->permModify())
 				{
diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index 6e61584d33f4d70ceb9cb4572d86de5608b0c6d0..32fb33f734c5ff44e7ae3ec6bed366b0756222f9 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -319,11 +319,12 @@ void LLPanelPrimMediaControls::updateShape()
 		bool hasPermsControl = true;
 		bool mini_controls = false;
 		LLMediaEntry *media_data = objectp->getTE(mTargetObjectFace)->getMediaData();
-		if (media_data && NULL != dynamic_cast<LLVOVolume*>(objectp))
+        LLVOVolume *vol = objectp ? objectp->asVolume() : nullptr;
+		if (media_data && vol)
 		{
 			// Don't show the media controls if we do not have permissions
-			enabled = dynamic_cast<LLVOVolume*>(objectp)->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL);
-			hasPermsControl = dynamic_cast<LLVOVolume*>(objectp)->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL);
+			enabled = vol->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL);
+			hasPermsControl = vol->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL);
 			mini_controls = (LLMediaEntry::MINI == media_data->getControls());
 		}
 		const bool is_hud = objectp->isHUDAttachment();
@@ -805,12 +806,16 @@ void LLPanelPrimMediaControls::draw()
 	// draw control background UI image
 	
 	LLViewerObject* objectp = getTargetObject();
-	LLMediaEntry *media_data(0);
+	LLMediaEntry *media_data = nullptr;
+	LLVOVolume* volumep = nullptr;
 
 	if( objectp )
+	{
 		media_data = objectp->getTE(mTargetObjectFace)->getMediaData();
+		volumep = objectp->asVolume();
+	}
 
-	if( !dynamic_cast<LLVOVolume*>(objectp) || !media_data || dynamic_cast<LLVOVolume*>(objectp)->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL) )
+	if( !volumep || !media_data || volumep->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL) )
 		mBackgroundImage->draw( controls_bg_area, UI_VERTEX_COLOR % alpha);
 
 	// draw volume slider background UI image
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index f93a81fb56934007dd1816d649b96f5041213690..dce448cd53ddbaa74e62057de981e475bb59bd38 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2088,7 +2088,7 @@ void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data)
 					else {
 						// Add/update media
 						object->setTEMediaFlags(te, mMediaFlags);
-						LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object);
+						LLVOVolume *vo = object->asVolume();
 						llassert(NULL != vo);
 						if (NULL != vo) 
 						{
@@ -2114,7 +2114,7 @@ void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data)
 			if (object->permModify())
 			{
 				object->sendTEUpdate();
-				LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object);
+				LLVOVolume *vo = object->asVolume();
 				llassert(NULL != vo);
 				// It's okay to skip this object if hasMedia() is false...
 				// the sendTEUpdate() above would remove all media data if it were
@@ -7537,7 +7537,7 @@ S32 LLObjectSelection::getSelectedObjectRenderCost()
 						 ++child_iter)
 				   {
 					   LLViewerObject* child_obj = *child_iter;
-					   LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+					   LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr;
 					   if (child)
 					   {
 						   cost += child->getRenderCost(textures);
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index d651761f4af570e25e425686e8182b1f65274a85..1917a5a3e4f85009693bb5cbd425a3658145bdbc 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2033,7 +2033,7 @@ void renderComplexityDisplay(LLDrawable* drawablep)
 		return;
 	}
 
-	LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj);
+	LLVOVolume *voVol = vobj->asVolume();;
 
 	if (!voVol)
 	{
@@ -2052,8 +2052,8 @@ void renderComplexityDisplay(LLDrawable* drawablep)
 	LLViewerObject::const_child_list_t children = voVol->getChildren();
 	for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
 	{
-		const LLViewerObject *child = *iter;
-		const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child);
+		LLViewerObject *child = *iter;
+		LLVOVolume* child_volume = child ? child->asVolume() : nullptr;
 		if (child_volume)
 		{
 			cost += child_volume->getRenderCost(textures);
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index f86d7b131b0d2f7b4a2c0ad5685d0e5b2422853a..194fc5a9a76498f6a355e39be7f0c6112b316799 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4428,7 +4428,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data)
         return;
     }
     
-	LLVOVolume *volp = dynamic_cast<LLVOVolume*>(objp);
+	LLVOVolume *volp = objp->asVolume();
     if (!volp)
     {
 		LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index f1108f9ca5aa49fd8d059dfee59fa1b010912899..336261eb4f0cc3d4f975cf5a41d1fc99b051710d 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -3151,7 +3151,7 @@ void LLViewerObject::linkControlAvatar()
 {
     if (!getControlAvatar() && isRootEdit())
     {
-        LLVOVolume *volp = dynamic_cast<LLVOVolume*>(this);
+        LLVOVolume *volp = asVolume();
         if (!volp)
         {
             LL_WARNS() << "called with null or non-volume object" << LL_ENDL;
@@ -3972,7 +3972,9 @@ F32 LLViewerObject::recursiveGetScaledSurfaceArea() const
                  ++child_iter)
             {
                 LLViewerObject* child_obj = *child_iter;
-                LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+				if(!child_obj) continue;
+
+                LLVOVolume *child = child_obj->asVolume();
                 if (child && child->getVolume())
                 {
                     const LLVector3& scale = child->getScale();
@@ -5692,11 +5694,18 @@ bool LLViewerObject::isOwnerInMuteList(LLUUID id)
 	return muted;
 }
 
+// virtual 
 LLVOAvatar* LLViewerObject::asAvatar()
 {
 	return NULL;
 }
 
+// virtual 
+LLVOVolume* LLViewerObject::asVolume()
+{
+	return nullptr;
+}
+
 // If this object is directly or indirectly parented by an avatar,
 // return it.  Normally getAvatar() is the correct function to call;
 // it will give the avatar used for skinning.  The exception is with
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 809ad995d328082541f560aa9f272747133c7105..1ded01ee292a4cc5acb8ee2ccb0e582ca45526d7 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -61,6 +61,7 @@ class LLPipeline;
 class LLTextureEntry;
 class LLVOAvatar;
 class LLVOInventoryListener;
+class LLVOVolume;
 class LLViewerInventoryItem;
 class LLViewerObject;
 class LLViewerObjectMedia;
@@ -138,6 +139,7 @@ class LLViewerObject
 	BOOL isParticleSource() const;
 
 	virtual LLVOAvatar* asAvatar();
+	virtual LLVOVolume* asVolume();
 
 	LLVOAvatar* getAvatarAncestor();
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 81ddbcd220ec6dc1d460f34d8d757f1ca87d6863..ff2723b5fe03819f36a90b49484ace2f99af9534 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1192,7 +1192,8 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
 
 					LL_DEBUGS() << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << LL_ENDL;
 
-					LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject()));
+					LLViewerObject* vobjp = static_cast<LLViewerObject*>(pick_info.getObject());
+					LLVOVolume *obj = vobjp ? vobjp->asVolume() : nullptr;
 				
 					if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty())
 					{
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f20b082d8c71c8c8d295325f1beae3f54c20433a..126e8de893b7b791df0134bc8237de949f9fa5b1 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1382,15 +1382,15 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 				 ++attachment_iter)
 			{
                     // Don't we need to look at children of attached_object as well?
-                const LLViewerObject* attached_object = attachment_iter->get();
+                LLViewerObject* attached_object = attachment_iter->get();
 				if (attached_object && !attached_object->isHUDAttachment())
 				{
-                        const LLVOVolume *vol = dynamic_cast<const LLVOVolume*>(attached_object);
+                        const LLVOVolume *vol = attached_object->asVolume();
                         if (vol && vol->isAnimatedObject())
                         {
                             // Animated objects already have a bounding box in their control av, use that. 
                             // Could lag by a frame if there's no guarantee on order of processing for avatars.
-                            LLControlAvatar *cav = vol->getControlAvatar();
+                            const LLControlAvatar *cav = vol->getControlAvatar();
                             if (cav)
                             {
                                 LLVector4a cav_min;
@@ -1409,7 +1409,7 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 					LLDrawable* drawable = attached_object->mDrawable;
 					if (drawable && !drawable->isState(LLDrawable::RIGGED))
 					{
-						LLSpatialBridge* bridge = drawable->getSpatialBridge();
+						const LLSpatialBridge* bridge = drawable->getSpatialBridge();
 						if (bridge)
 						{
 							const LLVector4a* ext = bridge->getSpatialExtents();
@@ -6235,7 +6235,7 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LL
         }
 	}
 
-	LLVOVolume *vobj = dynamic_cast<LLVOVolume*>(vo);
+	LLVOVolume *vobj = vo->asVolume();
 	bool pelvisGotSet = false;
 
 	if (!vobj)
@@ -7632,12 +7632,12 @@ void LLVOAvatar::rebuildAttachments()
 	{
 		for (LLViewerObject* pAttachObj : kvpAttachPt.second->mAttachedObjects)
 		{
-			if (LLVOVolume* pAttachVol = (pAttachObj->isMesh()) ? dynamic_cast<LLVOVolume*>(pAttachObj) : nullptr)
+			if (LLVOVolume* pAttachVol = (pAttachObj->isMesh()) ? pAttachObj->asVolume() : nullptr)
 			{
 				pAttachVol->forceLOD(3);
 				for (LLViewerObject* pChildObj : pAttachObj->getChildren())
 				{
-					if (LLVOVolume* pChildVol = (pChildObj->isMesh()) ? dynamic_cast<LLVOVolume*>(pChildObj) : nullptr)
+					if (LLVOVolume* pChildVol = (pChildObj->isMesh()) ? pChildObj->asVolume() : nullptr)
 						pAttachVol->forceLOD(3);
 				}
 			}
@@ -9978,11 +9978,12 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
 		LLViewerJointAttachment* attachment = iter->second;
 		LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_end = attachment->mAttachedObjects.end();
 		
-		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_iter = attachment->mAttachedObjects.begin();
-			 attach_iter != attach_end; ++attach_iter)
+		for (LLViewerObject* attached_object : attachment->mAttachedObjects)
 		{
-			LLViewerObject* attached_object =  attach_iter->get();
-            LLVOVolume *volume = dynamic_cast<LLVOVolume*>(attached_object);
+			if (!attached_object)
+				continue;
+
+            LLVOVolume *volume = attached_object->asVolume();
             if (volume)
             {
                 volumes.push_back(volume);
@@ -9995,11 +9996,12 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
                 }
             }
             LLViewerObject::const_child_list_t& children = attached_object->getChildren();
-            for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
-                 it != children.end(); ++it)
+            for (LLViewerObject* childp : children)
             {
-                LLViewerObject *childp = *it;
-                LLVOVolume *volume = dynamic_cast<LLVOVolume*>(childp);
+				if (!childp) 
+					continue;
+
+                LLVOVolume *volume = childp->asVolume();
                 if (volume)
                 {
                     volumes.push_back(volume);
@@ -10016,11 +10018,9 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
         {
             volumes.push_back(volp);
             LLViewerObject::const_child_list_t& children = volp->getChildren();
-            for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
-                 it != children.end(); ++it)
+            for (LLViewerObject* childp : children)
             {
-                LLViewerObject *childp = *it;
-                LLVOVolume *volume = dynamic_cast<LLVOVolume*>(childp);
+                LLVOVolume *volume = childp ? childp->asVolume() : nullptr;
                 if (volume)
                 {
                     volumes.push_back(volume);
@@ -10345,7 +10345,7 @@ void LLVOAvatar::accountRenderComplexityForObject(
 								  ++child_iter)
 							{
 								LLViewerObject* child_obj = *child_iter;
-								LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+								LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr;
 								if (child)
 								{
 									attachment_children_cost += child->getRenderCost(textures);
@@ -10396,11 +10396,9 @@ void LLVOAvatar::accountRenderComplexityForObject(
                         hud_object_complexity.objectsCount++;
 
                         LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
-                        for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
-                            iter != child_list.end(); ++iter)
+                        for (LLViewerObject* childp : child_list)
                         {
-                            LLViewerObject* childp = *iter;
-                            const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp);
+                            const LLVOVolume* chld_volume = childp ? childp->asVolume() : nullptr;
                             if (chld_volume)
                             {
                                 // get cost and individual textures
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index a78c248c33eeb818788a214ae30c1a03bec27a3d..c30d74f62fa373cc474d70187dba8b82fe66b4fd 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -267,6 +267,11 @@ LLVOVolume::~LLVOVolume()
 	}
 }
 
+LLVOVolume* LLVOVolume::asVolume()
+{
+	return this;
+}
+
 void LLVOVolume::markDead()
 {
 	if (!mDead)
@@ -1324,7 +1329,7 @@ std::string get_debug_object_lod_text(LLVOVolume *rootp)
          iter != child_list.end(); ++iter)
     {
         LLViewerObject *childp = *iter;
-        LLVOVolume *volp = dynamic_cast<LLVOVolume*>(childp);
+        LLVOVolume *volp = childp ? childp->asVolume() : nullptr;
         if (volp)
         {
             lod_string += llformat("%d",volp->getLOD());
@@ -3674,8 +3679,6 @@ bool LLVOVolume::isAnimatedObject() const
 // virtual
 void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent)
 {
-    LLVOVolume *old_volp = dynamic_cast<LLVOVolume*>(old_parent);
-
     if (new_parent && !new_parent->isAvatar())
     {
         if (mControlAvatar.notNull())
@@ -3687,7 +3690,9 @@ void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_pare
             av->markForDeath();
         }
     }
-    if (old_volp && old_volp->isAnimatedObject())
+
+	LLVOVolume *old_volp = old_parent ? old_parent->asVolume() : nullptr;
+	if (old_volp && old_volp->isAnimatedObject())
     {
         if (old_volp->getControlAvatar())
         {
@@ -5442,7 +5447,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	if (bridge)
 	{
         vobj = bridge->mDrawable->getVObj();
-        vol_obj = dynamic_cast<LLVOVolume*>(vobj);
+        vol_obj = vobj ? vobj->asVolume() : nullptr;
 	}
     if (vol_obj)
     {
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index d9f40de9449d2e62103aad3313aa5f0c9e3a12ed..e42a0081628a147ecc3c43f9cc78d069a061cf22 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -115,6 +115,7 @@ class LLVOVolume : public LLViewerObject
 
 public:
 						LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
+				LLVOVolume* asVolume();
 	/*virtual*/ void markDead();		// Override (and call through to parent) to clean up media references
 
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);